@pascal-app/nodes 1.0.0 → 1.0.3

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 (439) hide show
  1. package/dist/block/definition.d.ts.map +1 -1
  2. package/dist/block/definition.js +4 -1
  3. package/dist/block/face-host.d.ts.map +1 -1
  4. package/dist/block/face-host.js +19 -2
  5. package/dist/block/hosted-edit.d.ts +13 -0
  6. package/dist/block/hosted-edit.d.ts.map +1 -0
  7. package/dist/block/hosted-edit.js +205 -0
  8. package/dist/block/last-operation.d.ts +1 -1
  9. package/dist/block/last-operation.d.ts.map +1 -1
  10. package/dist/block/last-operation.js +6 -4
  11. package/dist/block/modal-session.d.ts +2 -1
  12. package/dist/block/modal-session.d.ts.map +1 -1
  13. package/dist/block/modal-session.js +2 -2
  14. package/dist/block/selection.d.ts.map +1 -1
  15. package/dist/block/selection.js +82 -24
  16. package/dist/block/surface.d.ts +4 -0
  17. package/dist/block/surface.d.ts.map +1 -0
  18. package/dist/block/surface.js +54 -0
  19. package/dist/block/use-block-face-operation.d.ts +2 -2
  20. package/dist/block/use-block-face-operation.d.ts.map +1 -1
  21. package/dist/block/use-block-face-operation.js +25 -11
  22. package/dist/box-vent/definition.d.ts.map +1 -1
  23. package/dist/box-vent/definition.js +1 -0
  24. package/dist/box-vent/panel.js +4 -4
  25. package/dist/building/renderer.d.ts.map +1 -1
  26. package/dist/building/renderer.js +1 -1
  27. package/dist/cabinet/appliance-layout.d.ts +26 -0
  28. package/dist/cabinet/appliance-layout.d.ts.map +1 -0
  29. package/dist/cabinet/appliance-layout.js +52 -0
  30. package/dist/cabinet/countertop-layout.d.ts +173 -0
  31. package/dist/cabinet/countertop-layout.d.ts.map +1 -0
  32. package/dist/cabinet/countertop-layout.js +80 -0
  33. package/dist/cabinet/definition.d.ts.map +1 -1
  34. package/dist/cabinet/definition.js +17 -8
  35. package/dist/cabinet/geometry/cooktop.d.ts.map +1 -1
  36. package/dist/cabinet/geometry/cooktop.js +2 -2
  37. package/dist/cabinet/geometry/run.d.ts.map +1 -1
  38. package/dist/cabinet/geometry/run.js +10 -71
  39. package/dist/cabinet/geometry/sink.d.ts +2 -12
  40. package/dist/cabinet/geometry/sink.d.ts.map +1 -1
  41. package/dist/cabinet/geometry/sink.js +8 -39
  42. package/dist/cabinet/hosted-resize.d.ts +5 -0
  43. package/dist/cabinet/hosted-resize.d.ts.map +1 -0
  44. package/dist/cabinet/hosted-resize.js +14 -0
  45. package/dist/cabinet/placement-snap.d.ts.map +1 -1
  46. package/dist/cabinet/placement-snap.js +4 -2
  47. package/dist/cabinet/run-layout.d.ts +8 -1
  48. package/dist/cabinet/run-layout.d.ts.map +1 -1
  49. package/dist/cabinet/run-layout.js +22 -14
  50. package/dist/cabinet/run-ops.d.ts +3 -3
  51. package/dist/cabinet/run-ops.js +3 -3
  52. package/dist/cabinet/run-panel.d.ts +1 -1
  53. package/dist/cabinet/run-panel.d.ts.map +1 -1
  54. package/dist/cabinet/run-panel.js +16 -7
  55. package/dist/cabinet/surfaces.d.ts +5 -0
  56. package/dist/cabinet/surfaces.d.ts.map +1 -0
  57. package/dist/cabinet/surfaces.js +113 -0
  58. package/dist/cabinet/tool.d.ts.map +1 -1
  59. package/dist/cabinet/tool.js +8 -4
  60. package/dist/cabinet/tree-structure.d.ts.map +1 -1
  61. package/dist/cabinet/tree-structure.js +10 -9
  62. package/dist/ceiling/definition.d.ts.map +1 -1
  63. package/dist/ceiling/definition.js +6 -1
  64. package/dist/ceiling/floorplan-affordances.d.ts +4 -4
  65. package/dist/ceiling/panel.js +1 -1
  66. package/dist/ceiling/renderer.d.ts.map +1 -1
  67. package/dist/ceiling/renderer.js +3 -2
  68. package/dist/chimney/definition.d.ts.map +1 -1
  69. package/dist/chimney/definition.js +1 -0
  70. package/dist/chimney/panel.js +9 -9
  71. package/dist/column/definition.d.ts.map +1 -1
  72. package/dist/column/definition.js +10 -3
  73. package/dist/column/floorplan-affordances.d.ts.map +1 -1
  74. package/dist/column/floorplan-affordances.js +6 -1
  75. package/dist/column/floorplan.d.ts.map +1 -1
  76. package/dist/column/floorplan.js +23 -11
  77. package/dist/column/hosted-resize.d.ts +116 -0
  78. package/dist/column/hosted-resize.d.ts.map +1 -0
  79. package/dist/column/hosted-resize.js +9 -0
  80. package/dist/column/panel.d.ts.map +1 -1
  81. package/dist/column/panel.js +6 -3
  82. package/dist/column/renderer.d.ts.map +1 -1
  83. package/dist/column/renderer.js +25 -103
  84. package/dist/column/shape.d.ts +22 -0
  85. package/dist/column/shape.d.ts.map +1 -0
  86. package/dist/column/shape.js +120 -0
  87. package/dist/column/surface.d.ts +4 -0
  88. package/dist/column/surface.d.ts.map +1 -0
  89. package/dist/column/surface.js +66 -0
  90. package/dist/cupola/definition.d.ts.map +1 -1
  91. package/dist/cupola/definition.js +1 -0
  92. package/dist/cupola/panel.js +1 -1
  93. package/dist/door/definition.d.ts.map +1 -1
  94. package/dist/door/definition.js +40 -1
  95. package/dist/door/door-math.d.ts +1 -1
  96. package/dist/door/door-math.d.ts.map +1 -1
  97. package/dist/door/door-math.js +7 -10
  98. package/dist/door/floorplan-affordances.d.ts.map +1 -1
  99. package/dist/door/floorplan-affordances.js +8 -12
  100. package/dist/door/move-tool.d.ts.map +1 -1
  101. package/dist/door/move-tool.js +3 -4
  102. package/dist/door/panel.d.ts.map +1 -1
  103. package/dist/door/panel.js +28 -57
  104. package/dist/door/tool.d.ts.map +1 -1
  105. package/dist/door/tool.js +20 -2
  106. package/dist/dormer/definition.d.ts.map +1 -1
  107. package/dist/dormer/definition.js +1 -0
  108. package/dist/dormer/panel-position-section.js +2 -2
  109. package/dist/dormer/panel.js +1 -1
  110. package/dist/downspout/definition.d.ts.map +1 -1
  111. package/dist/downspout/definition.js +1 -0
  112. package/dist/duct-segment/parametrics.d.ts.map +1 -1
  113. package/dist/duct-segment/parametrics.js +5 -1
  114. package/dist/duct-segment/tool.d.ts +1 -0
  115. package/dist/duct-segment/tool.d.ts.map +1 -1
  116. package/dist/duct-segment/tool.js +21 -8
  117. package/dist/duct-terminal/tool.d.ts.map +1 -1
  118. package/dist/duct-terminal/tool.js +77 -8
  119. package/dist/elevator/definition.d.ts.map +1 -1
  120. package/dist/elevator/definition.js +2 -0
  121. package/dist/elevator/parametrics.d.ts.map +1 -1
  122. package/dist/elevator/parametrics.js +98 -1
  123. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  124. package/dist/eyebrow-vent/definition.js +1 -0
  125. package/dist/eyebrow-vent/panel.js +1 -1
  126. package/dist/fence/definition.d.ts.map +1 -1
  127. package/dist/fence/definition.js +1 -0
  128. package/dist/fence/inspector-editors.js +1 -1
  129. package/dist/fence/tool.js +2 -2
  130. package/dist/guide/definition.d.ts.map +1 -1
  131. package/dist/guide/definition.js +1 -0
  132. package/dist/gutter/definition.d.ts.map +1 -1
  133. package/dist/gutter/definition.js +1 -0
  134. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  135. package/dist/hvac-equipment/tool.js +8 -2
  136. package/dist/imported-mesh/definition.d.ts +5 -0
  137. package/dist/imported-mesh/definition.d.ts.map +1 -0
  138. package/dist/imported-mesh/definition.js +38 -0
  139. package/dist/imported-mesh/floorplan.d.ts +4 -0
  140. package/dist/imported-mesh/floorplan.d.ts.map +1 -0
  141. package/dist/imported-mesh/floorplan.js +34 -0
  142. package/dist/imported-mesh/geometry.d.ts +5 -0
  143. package/dist/imported-mesh/geometry.d.ts.map +1 -0
  144. package/dist/imported-mesh/geometry.js +34 -0
  145. package/dist/imported-mesh/index.d.ts +4 -0
  146. package/dist/imported-mesh/index.d.ts.map +1 -0
  147. package/dist/imported-mesh/index.js +3 -0
  148. package/dist/imported-mesh/schema.d.ts +2 -0
  149. package/dist/imported-mesh/schema.d.ts.map +1 -0
  150. package/dist/imported-mesh/schema.js +1 -0
  151. package/dist/index.d.ts +2 -0
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +8 -0
  154. package/dist/item/__fixtures__/main-floorplan.d.ts +26 -0
  155. package/dist/item/__fixtures__/main-floorplan.d.ts.map +1 -0
  156. package/dist/item/__fixtures__/main-floorplan.js +297 -0
  157. package/dist/item/definition.d.ts.map +1 -1
  158. package/dist/item/definition.js +3 -1
  159. package/dist/item/floorplan-move.d.ts +9 -1
  160. package/dist/item/floorplan-move.d.ts.map +1 -1
  161. package/dist/item/floorplan-move.js +231 -99
  162. package/dist/item/floorplan.d.ts +22 -0
  163. package/dist/item/floorplan.d.ts.map +1 -1
  164. package/dist/item/floorplan.js +72 -2
  165. package/dist/item/move-tool.d.ts +1 -1
  166. package/dist/item/move-tool.d.ts.map +1 -1
  167. package/dist/item/move-tool.js +15 -7
  168. package/dist/item/panel.js +1 -1
  169. package/dist/item/renderer.d.ts.map +1 -1
  170. package/dist/item/renderer.js +8 -2
  171. package/dist/level/renderer.js +1 -1
  172. package/dist/lineset/tool.d.ts.map +1 -1
  173. package/dist/lineset/tool.js +1 -0
  174. package/dist/liquid-line/tool.d.ts.map +1 -1
  175. package/dist/liquid-line/tool.js +5 -1
  176. package/dist/measurement/definition.d.ts.map +1 -1
  177. package/dist/measurement/definition.js +1 -0
  178. package/dist/pipe-segment/parametrics.d.ts.map +1 -1
  179. package/dist/pipe-segment/parametrics.js +5 -1
  180. package/dist/pipe-segment/tool.d.ts.map +1 -1
  181. package/dist/pipe-segment/tool.js +14 -3
  182. package/dist/pipe-trap/tool.d.ts.map +1 -1
  183. package/dist/pipe-trap/tool.js +7 -8
  184. package/dist/procedural-item/definition.d.ts +4 -0
  185. package/dist/procedural-item/definition.d.ts.map +1 -0
  186. package/dist/procedural-item/definition.js +257 -0
  187. package/dist/procedural-item/geometry.d.ts +31 -0
  188. package/dist/procedural-item/geometry.d.ts.map +1 -0
  189. package/dist/procedural-item/geometry.js +88 -0
  190. package/dist/procedural-item/index.d.ts +3 -0
  191. package/dist/procedural-item/index.d.ts.map +1 -0
  192. package/dist/procedural-item/index.js +2 -0
  193. package/dist/procedural-item/move-session.d.ts +15 -0
  194. package/dist/procedural-item/move-session.d.ts.map +1 -0
  195. package/dist/procedural-item/move-session.js +197 -0
  196. package/dist/procedural-item/move-tool.d.ts +5 -0
  197. package/dist/procedural-item/move-tool.d.ts.map +1 -0
  198. package/dist/procedural-item/move-tool.js +193 -0
  199. package/dist/procedural-item/renderer.d.ts +5 -0
  200. package/dist/procedural-item/renderer.d.ts.map +1 -0
  201. package/dist/procedural-item/renderer.js +66 -0
  202. package/dist/ridge-vent/definition.d.ts.map +1 -1
  203. package/dist/ridge-vent/definition.js +1 -0
  204. package/dist/ridge-vent/panel.js +4 -4
  205. package/dist/roof/definition.d.ts.map +1 -1
  206. package/dist/roof/definition.js +4 -1
  207. package/dist/roof/panel-model.d.ts +4 -0
  208. package/dist/roof/panel-model.d.ts.map +1 -0
  209. package/dist/roof/panel-model.js +151 -0
  210. package/dist/roof/panel.d.ts.map +1 -1
  211. package/dist/roof/panel.js +9 -8
  212. package/dist/roof/parametrics.d.ts.map +1 -1
  213. package/dist/roof/parametrics.js +16 -1
  214. package/dist/roof-segment/definition.d.ts.map +1 -1
  215. package/dist/roof-segment/definition.js +1 -0
  216. package/dist/roof-segment/panel.d.ts.map +1 -1
  217. package/dist/roof-segment/panel.js +5 -5
  218. package/dist/roof-segment/parametrics.d.ts.map +1 -1
  219. package/dist/roof-segment/parametrics.js +176 -1
  220. package/dist/scan/definition.d.ts.map +1 -1
  221. package/dist/scan/definition.js +1 -0
  222. package/dist/shared/automatic-run-end-cap.d.ts +1 -0
  223. package/dist/shared/automatic-run-end-cap.d.ts.map +1 -1
  224. package/dist/shared/automatic-run-end-cap.js +10 -0
  225. package/dist/shared/commit-opening-move.d.ts +4 -0
  226. package/dist/shared/commit-opening-move.d.ts.map +1 -0
  227. package/dist/shared/commit-opening-move.js +9 -0
  228. package/dist/shared/curtain-opening-limits.d.ts +14 -0
  229. package/dist/shared/curtain-opening-limits.d.ts.map +1 -0
  230. package/dist/shared/curtain-opening-limits.js +53 -0
  231. package/dist/shared/distribution-run-tool.d.ts +10 -0
  232. package/dist/shared/distribution-run-tool.d.ts.map +1 -1
  233. package/dist/shared/distribution-run-tool.js +56 -11
  234. package/dist/shared/draft-axis-guides.d.ts +0 -6
  235. package/dist/shared/draft-axis-guides.d.ts.map +1 -1
  236. package/dist/shared/draft-axis-guides.js +1 -8
  237. package/dist/shared/hosted-resize.d.ts +12 -0
  238. package/dist/shared/hosted-resize.d.ts.map +1 -0
  239. package/dist/shared/hosted-resize.js +166 -0
  240. package/dist/shared/opening-grid-follow.d.ts +8 -0
  241. package/dist/shared/opening-grid-follow.d.ts.map +1 -0
  242. package/dist/shared/opening-grid-follow.js +12 -0
  243. package/dist/shared/opening-property-preview-host.d.ts +3 -0
  244. package/dist/shared/opening-property-preview-host.d.ts.map +1 -0
  245. package/dist/shared/opening-property-preview-host.js +21 -0
  246. package/dist/shared/opening-property-preview.d.ts +19 -0
  247. package/dist/shared/opening-property-preview.d.ts.map +1 -0
  248. package/dist/shared/opening-property-preview.js +99 -0
  249. package/dist/shared/panel-fields.d.ts +15 -0
  250. package/dist/shared/panel-fields.d.ts.map +1 -0
  251. package/dist/shared/panel-fields.js +31 -0
  252. package/dist/shared/resting-surface-plan.d.ts +4 -0
  253. package/dist/shared/resting-surface-plan.d.ts.map +1 -0
  254. package/dist/shared/resting-surface-plan.js +53 -0
  255. package/dist/shared/surface-counterparts.d.ts +12 -0
  256. package/dist/shared/surface-counterparts.d.ts.map +1 -0
  257. package/dist/shared/surface-counterparts.js +27 -0
  258. package/dist/shared/wall-attach-target.d.ts +1 -0
  259. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  260. package/dist/shared/wall-attach-target.js +4 -1
  261. package/dist/shared/wall-event-from-grid.d.ts +5 -0
  262. package/dist/shared/wall-event-from-grid.d.ts.map +1 -0
  263. package/dist/shared/wall-event-from-grid.js +36 -0
  264. package/dist/shelf/definition.d.ts.map +1 -1
  265. package/dist/shelf/definition.js +5 -2
  266. package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
  267. package/dist/shelf/floorplan-affordances.js +5 -3
  268. package/dist/shelf/floorplan-move.d.ts.map +1 -1
  269. package/dist/shelf/floorplan-move.js +3 -2
  270. package/dist/shelf/floorplan.d.ts.map +1 -1
  271. package/dist/shelf/floorplan.js +9 -2
  272. package/dist/shelf/geometry.d.ts.map +1 -1
  273. package/dist/shelf/geometry.js +2 -10
  274. package/dist/site/renderer.d.ts.map +1 -1
  275. package/dist/site/renderer.js +9 -2
  276. package/dist/skylight/definition.d.ts.map +1 -1
  277. package/dist/skylight/definition.js +1 -0
  278. package/dist/skylight/panel.js +6 -6
  279. package/dist/slab/definition.d.ts.map +1 -1
  280. package/dist/slab/definition.js +4 -0
  281. package/dist/slab/panel.js +1 -1
  282. package/dist/solar-panel/definition.d.ts.map +1 -1
  283. package/dist/solar-panel/definition.js +1 -0
  284. package/dist/solar-panel/panel.js +2 -2
  285. package/dist/spawn/definition.d.ts.map +1 -1
  286. package/dist/spawn/definition.js +1 -0
  287. package/dist/spawn/panel.js +1 -1
  288. package/dist/stair/definition.d.ts.map +1 -1
  289. package/dist/stair/definition.js +2 -0
  290. package/dist/stair/panel.d.ts.map +1 -1
  291. package/dist/stair/panel.js +9 -7
  292. package/dist/stair/parametrics.d.ts.map +1 -1
  293. package/dist/stair/parametrics.js +164 -1
  294. package/dist/stair-segment/definition.d.ts.map +1 -1
  295. package/dist/stair-segment/definition.js +1 -0
  296. package/dist/stair-segment/panel.js +4 -4
  297. package/dist/stair-segment/parametrics.d.ts.map +1 -1
  298. package/dist/stair-segment/parametrics.js +81 -1
  299. package/dist/turbine-vent/definition.d.ts.map +1 -1
  300. package/dist/turbine-vent/definition.js +1 -0
  301. package/dist/turbine-vent/panel.js +1 -1
  302. package/dist/unit/definition.d.ts +10 -0
  303. package/dist/unit/definition.d.ts.map +1 -0
  304. package/dist/unit/definition.js +38 -0
  305. package/dist/unit/index.d.ts +2 -0
  306. package/dist/unit/index.d.ts.map +1 -0
  307. package/dist/unit/index.js +1 -0
  308. package/dist/unit/parametrics.d.ts +3 -0
  309. package/dist/unit/parametrics.d.ts.map +1 -0
  310. package/dist/unit/parametrics.js +4 -0
  311. package/dist/unit/schema.d.ts +2 -0
  312. package/dist/unit/schema.d.ts.map +1 -0
  313. package/dist/unit/schema.js +1 -0
  314. package/dist/unit/unit-panel.d.ts +5 -0
  315. package/dist/unit/unit-panel.d.ts.map +1 -0
  316. package/dist/unit/unit-panel.js +61 -0
  317. package/dist/wall/actions.d.ts +3 -0
  318. package/dist/wall/actions.d.ts.map +1 -0
  319. package/dist/wall/actions.js +56 -0
  320. package/dist/wall/curtain-opening-frame.d.ts +14 -0
  321. package/dist/wall/curtain-opening-frame.d.ts.map +1 -0
  322. package/dist/wall/curtain-opening-frame.js +111 -0
  323. package/dist/wall/curtain-panel-highlight.d.ts +3 -0
  324. package/dist/wall/curtain-panel-highlight.d.ts.map +1 -0
  325. package/dist/wall/curtain-panel-highlight.js +113 -0
  326. package/dist/wall/curtain-wall-adapter.d.ts +3 -0
  327. package/dist/wall/curtain-wall-adapter.d.ts.map +1 -0
  328. package/dist/wall/curtain-wall-adapter.js +55 -0
  329. package/dist/wall/curtain-wall-floorplan.d.ts +3 -0
  330. package/dist/wall/curtain-wall-floorplan.d.ts.map +1 -0
  331. package/dist/wall/curtain-wall-floorplan.js +91 -0
  332. package/dist/wall/curtain-wall-geometry.d.ts +4 -0
  333. package/dist/wall/curtain-wall-geometry.d.ts.map +1 -0
  334. package/dist/wall/curtain-wall-geometry.js +226 -0
  335. package/dist/wall/curtain-wall-layout.d.ts +16 -0
  336. package/dist/wall/curtain-wall-layout.d.ts.map +1 -0
  337. package/dist/wall/curtain-wall-layout.js +176 -0
  338. package/dist/wall/curtain-wall-materials.d.ts +5 -0
  339. package/dist/wall/curtain-wall-materials.d.ts.map +1 -0
  340. package/dist/wall/curtain-wall-materials.js +55 -0
  341. package/dist/wall/curtain-wall-panel.d.ts +14 -0
  342. package/dist/wall/curtain-wall-panel.d.ts.map +1 -0
  343. package/dist/wall/curtain-wall-panel.js +167 -0
  344. package/dist/wall/curtain-wall-piece-geometry.d.ts +5 -0
  345. package/dist/wall/curtain-wall-piece-geometry.d.ts.map +1 -0
  346. package/dist/wall/curtain-wall-piece-geometry.js +220 -0
  347. package/dist/wall/curtain-wall-shadow.d.ts +4 -0
  348. package/dist/wall/curtain-wall-shadow.d.ts.map +1 -0
  349. package/dist/wall/curtain-wall-shadow.js +15 -0
  350. package/dist/wall/definition.d.ts +0 -15
  351. package/dist/wall/definition.d.ts.map +1 -1
  352. package/dist/wall/definition.js +65 -4
  353. package/dist/wall/drawing-mode.d.ts +12 -0
  354. package/dist/wall/drawing-mode.d.ts.map +1 -0
  355. package/dist/wall/drawing-mode.js +38 -0
  356. package/dist/wall/floorplan-tool.d.ts +4 -0
  357. package/dist/wall/floorplan-tool.d.ts.map +1 -0
  358. package/dist/wall/floorplan-tool.js +107 -0
  359. package/dist/wall/floorplan.d.ts.map +1 -1
  360. package/dist/wall/floorplan.js +6 -2
  361. package/dist/wall/length-patch.d.ts +3 -0
  362. package/dist/wall/length-patch.d.ts.map +1 -0
  363. package/dist/wall/length-patch.js +14 -0
  364. package/dist/wall/move-tool.d.ts.map +1 -1
  365. package/dist/wall/move-tool.js +23 -1
  366. package/dist/wall/paint.d.ts.map +1 -1
  367. package/dist/wall/paint.js +39 -4
  368. package/dist/wall/panel-model.d.ts +4 -0
  369. package/dist/wall/panel-model.d.ts.map +1 -0
  370. package/dist/wall/panel-model.js +117 -0
  371. package/dist/wall/panel.d.ts.map +1 -1
  372. package/dist/wall/panel.js +20 -24
  373. package/dist/wall/property-preview.d.ts +7 -0
  374. package/dist/wall/property-preview.d.ts.map +1 -0
  375. package/dist/wall/property-preview.js +31 -0
  376. package/dist/wall/rectangle-command.d.ts +149 -0
  377. package/dist/wall/rectangle-command.d.ts.map +1 -0
  378. package/dist/wall/rectangle-command.js +22 -0
  379. package/dist/wall/rectangle-tool.d.ts +2 -0
  380. package/dist/wall/rectangle-tool.d.ts.map +1 -0
  381. package/dist/wall/rectangle-tool.js +147 -0
  382. package/dist/wall/renderer.d.ts.map +1 -1
  383. package/dist/wall/renderer.js +7 -4
  384. package/dist/wall/slots.d.ts +2 -2
  385. package/dist/wall/slots.d.ts.map +1 -1
  386. package/dist/wall/slots.js +10 -2
  387. package/dist/wall/split-floorplan-layer.d.ts +4 -0
  388. package/dist/wall/split-floorplan-layer.d.ts.map +1 -0
  389. package/dist/wall/split-floorplan-layer.js +71 -0
  390. package/dist/wall/split-pointer.d.ts +3 -0
  391. package/dist/wall/split-pointer.d.ts.map +1 -0
  392. package/dist/wall/split-pointer.js +95 -0
  393. package/dist/wall/split-preview.d.ts +55 -0
  394. package/dist/wall/split-preview.d.ts.map +1 -0
  395. package/dist/wall/split-preview.js +106 -0
  396. package/dist/wall/split-session.d.ts +16 -0
  397. package/dist/wall/split-session.d.ts.map +1 -0
  398. package/dist/wall/split-session.js +138 -0
  399. package/dist/wall/split-store.d.ts +16 -0
  400. package/dist/wall/split-store.d.ts.map +1 -0
  401. package/dist/wall/split-store.js +6 -0
  402. package/dist/wall/split-tool.d.ts +10 -0
  403. package/dist/wall/split-tool.d.ts.map +1 -0
  404. package/dist/wall/split-tool.js +95 -0
  405. package/dist/wall/system.d.ts.map +1 -1
  406. package/dist/wall/system.js +3 -1
  407. package/dist/wall/tool.d.ts.map +1 -1
  408. package/dist/wall/tool.js +14 -6
  409. package/dist/wall/wall-batch-system.d.ts.map +1 -1
  410. package/dist/wall/wall-batch-system.js +3 -0
  411. package/dist/window/definition.d.ts.map +1 -1
  412. package/dist/window/definition.js +48 -1
  413. package/dist/window/floorplan-affordances.d.ts.map +1 -1
  414. package/dist/window/floorplan-affordances.js +8 -10
  415. package/dist/window/move-tool.d.ts.map +1 -1
  416. package/dist/window/move-tool.js +4 -6
  417. package/dist/window/panel.d.ts.map +1 -1
  418. package/dist/window/panel.js +22 -60
  419. package/dist/window/tool.d.ts.map +1 -1
  420. package/dist/window/tool.js +34 -2
  421. package/dist/window/window-math.d.ts +1 -1
  422. package/dist/window/window-math.d.ts.map +1 -1
  423. package/dist/window/window-math.js +8 -11
  424. package/dist/zone/definition.d.ts.map +1 -1
  425. package/dist/zone/definition.js +8 -1
  426. package/dist/zone/floorplan.d.ts +1 -3
  427. package/dist/zone/floorplan.d.ts.map +1 -1
  428. package/dist/zone/floorplan.js +43 -28
  429. package/dist/zone/quantities-panel.d.ts.map +1 -1
  430. package/dist/zone/quantities-panel.js +32 -44
  431. package/dist/zone/renderer.d.ts.map +1 -1
  432. package/dist/zone/renderer.js +21 -7
  433. package/dist/zone/unit-membership.d.ts +12 -0
  434. package/dist/zone/unit-membership.d.ts.map +1 -0
  435. package/dist/zone/unit-membership.js +22 -0
  436. package/package.json +15 -9
  437. package/dist/shared/opening-documentation-fields.d.ts +0 -16
  438. package/dist/shared/opening-documentation-fields.d.ts.map +0 -1
  439. package/dist/shared/opening-documentation-fields.js +0 -54
@@ -2,10 +2,9 @@ import { resolveAutoZonePolygon, } from '@pascal-app/core';
2
2
  import { floorplanGeometryMetadata, readFloorplanContext } from '@pascal-app/editor';
3
3
  import { formatConstructionLength, } from '../shared/construction-length';
4
4
  import { buildRoomClearDimensions } from './room-clear-dimensions';
5
+ import { owningUnitForZone } from './unit-membership';
5
6
  /**
6
- * Stage C floor-plan builder for zone. Zones are colored polygons —
7
- * fill + outline both come from `zone.color`. Selection adds an
8
- * accent-colored outline.
7
+ * Stage C floor-plan builder for zone. Zones are colored polygons.
9
8
  *
10
9
  * The zone's `name` renders as a centered text label at the polygon's
11
10
  * geometric centroid. The registry layer sorts zones before every
@@ -18,23 +17,25 @@ export function buildZoneFloorplan(node, ctx) {
18
17
  return null;
19
18
  const view = ctx.viewState;
20
19
  const floorplanContext = readFloorplanContext(ctx);
21
- const palette = view?.palette;
22
20
  const isSelected = view?.selected ?? false;
23
21
  const isHighlighted = view?.highlighted ?? false;
24
22
  const showSelectedChrome = isSelected || isHighlighted;
25
23
  const points = ring.map(([x, z]) => [x, z]);
26
- const stroke = showSelectedChrome && palette ? palette.selectedStroke : node.color;
24
+ const unit = owningUnitForZone(node, ctx.resolve);
25
+ const tintColor = unit?.color ?? node.color;
26
+ const stroke = node.color;
27
+ const focusOpacity = view?.focusedUnitId && !view.focusedUnitMemberIds?.includes(node.id) ? 0.35 : 1;
27
28
  const isRoom = node.spaceRole === 'room';
28
29
  const fillOpacity = isRoom ? (isSelected ? 0.12 : 0.04) : isSelected ? 0.28 : 0.16;
29
30
  const children = [
30
31
  {
31
32
  kind: 'polygon',
32
33
  points,
33
- fill: node.color,
34
- fillOpacity,
34
+ fill: tintColor,
35
+ fillOpacity: fillOpacity * focusOpacity,
35
36
  stroke,
36
37
  strokeWidth: showSelectedChrome ? 0.08 : 0.05,
37
- strokeOpacity: showSelectedChrome ? 0.96 : 0.72,
38
+ strokeOpacity: (showSelectedChrome ? 0.96 : 0.72) * focusOpacity,
38
39
  strokeLinejoin: 'round',
39
40
  vectorEffect: 'non-scaling-stroke',
40
41
  },
@@ -88,44 +89,58 @@ export function buildZoneFloorplan(node, ctx) {
88
89
  const [cx, cy] = polygonCentroid(ring);
89
90
  const name = node.name?.trim();
90
91
  if (isRoom) {
91
- children.push(...buildRoomLabels(node, cx, cy, view?.unit ?? 'metric', floorplanContext.purpose === 'document' ? 'document' : 'editor', floorplanContext.metricNotation, stroke));
92
+ children.push(...buildRoomLabels(node, cx, cy, view?.unit ?? 'metric', floorplanContext.purpose === 'document' ? 'document' : 'editor', floorplanContext.metricNotation, stroke, unit?.name));
92
93
  if (floorplanContext.automaticDimensions) {
93
94
  children.push(...buildRoomClearDimensions(node, ctx));
94
95
  }
95
96
  }
96
97
  else if (name) {
97
- children.push({
98
- kind: 'text',
99
- x: cx,
100
- y: cy,
101
- text: name,
102
- // Same constants the legacy `FLOORPLAN_ZONE_LABEL_FONT_SIZE` uses
103
- // (0.2 plan metres ≈ readable at typical building zooms).
104
- fontSize: ZONE_LABEL_FONT_SIZE,
105
- fill: '#ffffff',
106
- stroke: node.color,
107
- strokeWidth: ZONE_LABEL_FONT_SIZE * 0.35,
108
- paintOrder: 'stroke',
109
- fontFamily: 'system-ui, -apple-system, sans-serif',
110
- fontWeight: 500,
111
- textAnchor: 'middle',
112
- dominantBaseline: 'central',
113
- opacity: showSelectedChrome ? 1 : 0.92,
114
- upright: true,
98
+ const unitName = unit?.name.trim();
99
+ const lines = unitName
100
+ ? [
101
+ { text: name, fontSize: ZONE_LABEL_FONT_SIZE, fontWeight: 500 },
102
+ { text: unitName, fontSize: ZONE_UNIT_LABEL_FONT_SIZE, fontWeight: 600 },
103
+ ]
104
+ : [{ text: name, fontSize: ZONE_LABEL_FONT_SIZE, fontWeight: 500 }];
105
+ const startY = cy - ((lines.length - 1) * ROOM_LABEL_LINE_SPACING) / 2;
106
+ lines.forEach((line, index) => {
107
+ children.push({
108
+ kind: 'text',
109
+ x: cx,
110
+ y: startY + index * ROOM_LABEL_LINE_SPACING,
111
+ text: line.text,
112
+ // Same constants the legacy `FLOORPLAN_ZONE_LABEL_FONT_SIZE` uses
113
+ // (0.2 plan metres ≈ readable at typical building zooms).
114
+ fontSize: line.fontSize,
115
+ fill: '#ffffff',
116
+ stroke: node.color,
117
+ strokeWidth: line.fontSize * 0.35,
118
+ paintOrder: 'stroke',
119
+ fontFamily: 'system-ui, -apple-system, sans-serif',
120
+ fontWeight: line.fontWeight,
121
+ textAnchor: 'middle',
122
+ dominantBaseline: 'central',
123
+ opacity: showSelectedChrome ? 1 : 0.92,
124
+ upright: true,
125
+ });
115
126
  });
116
127
  }
117
128
  return { kind: 'group', children };
118
129
  }
119
130
  const ZONE_LABEL_FONT_SIZE = 0.2;
131
+ const ZONE_UNIT_LABEL_FONT_SIZE = 0.13;
120
132
  const ROOM_NAME_FONT_SIZE = 0.2;
121
133
  const ROOM_NUMBER_FONT_SIZE = 0.16;
122
134
  const ROOM_DETAIL_FONT_SIZE = 0.11;
123
135
  const ROOM_LABEL_LINE_SPACING = 0.18;
124
- function buildRoomLabels(node, x, y, unit, profile, metricNotation, color) {
136
+ function buildRoomLabels(node, x, y, unit, profile, metricNotation, color, unitName) {
125
137
  const lines = [];
126
138
  const name = node.name.trim();
127
139
  if (name)
128
140
  lines.push({ text: name, fontSize: ROOM_NAME_FONT_SIZE, fontWeight: 700 });
141
+ if (unitName?.trim()) {
142
+ lines.push({ text: unitName.trim(), fontSize: ROOM_NUMBER_FONT_SIZE, fontWeight: 600 });
143
+ }
129
144
  if (node.roomNumber) {
130
145
  lines.push({ text: node.roomNumber, fontSize: ROOM_NUMBER_FONT_SIZE, fontWeight: 600 });
131
146
  }
@@ -1 +1 @@
1
- {"version":3,"file":"quantities-panel.d.ts","sourceRoot":"","sources":["../../src/zone/quantities-panel.tsx"],"names":[],"mappings":"AA8TA,MAAM,CAAC,OAAO,UAAU,mBAAmB,uCA6F1C"}
1
+ {"version":3,"file":"quantities-panel.d.ts","sourceRoot":"","sources":["../../src/zone/quantities-panel.tsx"],"names":[],"mappings":"AAsMA,MAAM,CAAC,OAAO,UAAU,mBAAmB,uCA6F1C"}
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { deriveZoneQuantityReport, resolveAutoZonePolygon, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
4
- import { formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, MetricControl, PanelSection, ToggleControl, } from '@pascal-app/editor';
4
+ import { formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, PanelSection, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
- import { useEffect, useMemo, useRef, useState } from 'react';
6
+ import { useMemo } from 'react';
7
7
  import { useShallow } from 'zustand/react/shallow';
8
+ import { PanelSelect } from '../shared/panel-fields';
9
+ import { buildingUnitsForZone } from './unit-membership';
8
10
  function ZonePlanSketch({ edgeLengths, metricNotation, polygon, unit, }) {
9
11
  if (polygon.length < 3) {
10
12
  return (_jsx("div", { className: "flex h-28 items-center justify-center rounded-md border border-border/50 text-muted-foreground text-xs", children: "Zone boundary unavailable" }));
@@ -44,49 +46,35 @@ function ZonePlanSketch({ edgeLengths, metricNotation, polygon, unit, }) {
44
46
  function QuantityRow({ abbreviation, format, label, quantity, }) {
45
47
  return (_jsxs("div", { className: "rounded-md border border-border/50 bg-background/35 px-2.5 py-2", children: [_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "font-mono font-semibold text-cyan-600 text-[10px]", children: abbreviation }), _jsx("span", { className: "text-muted-foreground text-xs", children: label }), _jsx("span", { className: "ml-auto font-mono font-medium text-foreground text-xs tabular-nums", children: quantity.status === 'available' ? format(quantity.value) : 'Not proven' })] }), _jsx("div", { className: "mt-1 text-[10px] text-muted-foreground leading-snug", children: quantity.status === 'available' ? quantity.note : quantity.reason })] }));
46
48
  }
47
- function RoomTextField({ label, onCommit, value, }) {
48
- const [draft, setDraft] = useState(value);
49
- const cancelRef = useRef(false);
50
- useEffect(() => setDraft(value), [value]);
51
- const commit = () => {
52
- if (cancelRef.current) {
53
- cancelRef.current = false;
54
- setDraft(value);
55
- return;
49
+ function ZoneUnitPanel({ zone }) {
50
+ const units = useScene(useShallow((state) => buildingUnitsForZone(zone, (id) => state.nodes[id])));
51
+ if (units.length === 0)
52
+ return null;
53
+ const current = units.find((unit) => unit.members.includes(zone.id));
54
+ const handleChange = (nextId) => {
55
+ const { nodes, updateNodes } = useScene.getState();
56
+ const updates = [];
57
+ for (const unit of Object.values(nodes)) {
58
+ if (unit.type !== 'unit')
59
+ continue;
60
+ const isMember = unit.members.includes(zone.id);
61
+ if (unit.id === nextId && !isMember) {
62
+ updates.push({ id: unit.id, data: { members: [...unit.members, zone.id] } });
63
+ }
64
+ else if (unit.id !== nextId && isMember) {
65
+ updates.push({
66
+ id: unit.id,
67
+ data: { members: unit.members.filter((id) => id !== zone.id) },
68
+ });
69
+ }
56
70
  }
57
- const next = draft.trim();
58
- if (next !== value)
59
- onCommit(next);
60
- else
61
- setDraft(value);
71
+ if (updates.length > 0)
72
+ updateNodes(updates);
62
73
  };
63
- return (_jsxs("label", { className: "flex h-10 items-center gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "shrink-0 text-muted-foreground", children: label }), _jsx("input", { className: "min-w-0 flex-1 bg-transparent text-right text-foreground outline-none selection:bg-primary/30", onBlur: commit, onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
64
- if (event.key === 'Enter')
65
- event.currentTarget.blur();
66
- if (event.key === 'Escape') {
67
- cancelRef.current = true;
68
- event.currentTarget.blur();
69
- }
70
- }, type: "text", value: draft })] }));
71
- }
72
- function RoomSelect({ label, onChange, options, value, }) {
73
- return (_jsxs("label", { className: "flex h-10 items-center justify-between gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: label }), _jsx("select", { className: "min-w-0 rounded-md border border-border/50 bg-[#232325] px-2 py-1 text-foreground text-xs outline-none", onChange: (event) => onChange(event.target.value), value: value, children: options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })] }));
74
- }
75
- function RoomDocumentationPanel({ zone }) {
76
- const updateNode = useScene((state) => state.updateNode);
77
- const update = (patch) => updateNode(zone.id, patch);
78
- const isRoom = zone.spaceRole === 'room';
79
- return (_jsxs(PanelSection, { title: "Room documentation", children: [_jsx(ToggleControl, { checked: isRoom, label: "Architectural room", onChange: (checked) => update({ spaceRole: checked ? 'room' : 'generic' }) }), isRoom ? (_jsxs(_Fragment, { children: [_jsx(RoomTextField, { label: "Room name", onCommit: (name) => update({ name }), value: zone.name }), _jsx(RoomTextField, { label: "Room number", onCommit: (roomNumber) => update({ roomNumber }), value: zone.roomNumber }), _jsx(RoomSelect, { label: "Enclosure", onChange: (enclosureStatus) => update({ enclosureStatus: enclosureStatus }), options: [
80
- { label: 'Auto-detect', value: 'auto' },
81
- { label: 'Enclosed', value: 'enclosed' },
82
- { label: 'Open', value: 'open' },
83
- ], value: zone.enclosureStatus }), _jsx(RoomTextField, { label: "Occupancy / use", onCommit: (occupancy) => update({ occupancy }), value: zone.occupancy }), _jsx(RoomTextField, { label: "Floor finish", onCommit: (floorFinish) => update({ floorFinish }), value: zone.floorFinish }), _jsx(RoomTextField, { label: "Wall finish", onCommit: (wallFinish) => update({ wallFinish }), value: zone.wallFinish }), _jsx(RoomTextField, { label: "Ceiling finish", onCommit: (ceilingFinish) => update({ ceilingFinish }), value: zone.ceilingFinish }), _jsx(MetricControl, { label: "Ceiling height", max: 20, min: 0.1, onChange: (ceilingHeight) => update({ ceilingHeight }), precision: 2, step: 0.05, unit: "m", value: zone.ceilingHeight }), _jsx(RoomSelect, { label: "Clear dimensions", onChange: (clearDimensionPolicy) => update({
84
- clearDimensionPolicy: clearDimensionPolicy,
85
- }), options: [
86
- { label: 'None', value: 'none' },
87
- { label: 'Inside faces', value: 'inside-faces' },
88
- { label: 'Finish faces', value: 'finish-faces' },
89
- ], value: zone.clearDimensionPolicy })] })) : null] }));
74
+ return (_jsx(PanelSection, { title: "Unit", children: _jsx(PanelSelect, { label: "Unit", onChange: handleChange, options: [
75
+ { label: 'None', value: '' },
76
+ ...units.map((unit) => ({ label: unit.name || 'Unit', value: unit.id })),
77
+ ], value: current?.id ?? '' }) }));
90
78
  }
91
79
  export default function ZoneQuantitiesPanel() {
92
80
  const selectedZoneId = useViewer((state) => state.selection.zoneId);
@@ -124,5 +112,5 @@ export default function ZoneQuantitiesPanel() {
124
112
  const report = useMemo(() => (effectiveZone ? deriveZoneQuantityReport(effectiveZone, effectiveNodes) : null), [effectiveNodes, effectiveZone]);
125
113
  if (!effectiveZone || !report)
126
114
  return null;
127
- return (_jsxs(_Fragment, { children: [_jsx(RoomDocumentationPanel, { zone: effectiveZone }), _jsxs(PanelSection, { title: effectiveZone.spaceRole === 'room' ? 'Room quantities' : 'Zone quantities', children: [_jsxs("div", { className: "overflow-hidden rounded-md border border-cyan-950/20 bg-[#f8faf7] text-slate-950", children: [_jsxs("div", { className: "flex items-center border-cyan-950/15 border-b px-2.5 py-2", children: [_jsx("span", { className: "font-semibold text-[11px]", children: effectiveZone.name }), _jsx("span", { className: "ml-auto rounded-full border border-cyan-800/25 bg-cyan-50 px-2 py-0.5 text-cyan-900 text-[9px]", children: report.classification === 'enclosed-room' ? 'Enclosed room' : 'Footprint only' })] }), _jsxs("div", { className: "flex items-baseline gap-2 px-2.5 py-2 font-mono text-[10px]", children: [_jsx("span", { className: "text-cyan-800", children: "A" }), _jsx("span", { children: formatAreaLabel(report.footprintArea, unit, 2) }), _jsx("span", { className: "ml-auto text-slate-600", children: "P" }), _jsx("span", { children: formatLinearMeasurement(report.perimeter, unit, metricNotation) })] })] }), _jsx(ZonePlanSketch, { edgeLengths: report.edgeLengths, metricNotation: metricNotation, polygon: effectiveZone.polygon, unit: unit }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(QuantityRow, { abbreviation: "Aw", format: (value) => formatAreaLabel(value, unit, 2), label: "Wall surface", quantity: report.wallSurface }), _jsx(QuantityRow, { abbreviation: "Af", format: (value) => formatAreaLabel(value, unit, 2), label: "Floor surface", quantity: report.floorSurface }), _jsx(QuantityRow, { abbreviation: "V", format: (value) => formatVolumeLabel(value, unit, 2), label: "Volume", quantity: report.volume })] })] })] }));
115
+ return (_jsxs(_Fragment, { children: [_jsx(ZoneUnitPanel, { zone: effectiveZone }), _jsxs(PanelSection, { title: effectiveZone.spaceRole === 'room' ? 'Room quantities' : 'Zone quantities', children: [_jsxs("div", { className: "overflow-hidden rounded-md border border-cyan-950/20 bg-[#f8faf7] text-slate-950", children: [_jsxs("div", { className: "flex items-center border-cyan-950/15 border-b px-2.5 py-2", children: [_jsx("span", { className: "font-semibold text-[11px]", children: effectiveZone.name }), _jsx("span", { className: "ml-auto rounded-full border border-cyan-800/25 bg-cyan-50 px-2 py-0.5 text-cyan-900 text-[9px]", children: report.classification === 'enclosed-room' ? 'Enclosed room' : 'Footprint only' })] }), _jsxs("div", { className: "flex items-baseline gap-2 px-2.5 py-2 font-mono text-[10px]", children: [_jsx("span", { className: "text-cyan-800", children: "A" }), _jsx("span", { children: formatAreaLabel(report.footprintArea, unit, 2) }), _jsx("span", { className: "ml-auto text-slate-600", children: "P" }), _jsx("span", { children: formatLinearMeasurement(report.perimeter, unit, metricNotation) })] })] }), _jsx(ZonePlanSketch, { edgeLengths: report.edgeLengths, metricNotation: metricNotation, polygon: effectiveZone.polygon, unit: unit }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(QuantityRow, { abbreviation: "Aw", format: (value) => formatAreaLabel(value, unit, 2), label: "Wall surface", quantity: report.wallSurface }), _jsx(QuantityRow, { abbreviation: "Af", format: (value) => formatAreaLabel(value, unit, 2), label: "Floor surface", quantity: report.floorSurface }), _jsx(QuantityRow, { abbreviation: "V", format: (value) => formatVolumeLabel(value, unit, 2), label: "Volume", quantity: report.volume })] })] })] }));
128
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/zone/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAyGzB,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,uCA0LxD,CAAA;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/zone/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AA0GzB,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,uCAoNxD,CAAA;AAED,eAAe,YAAY,CAAA"}
@@ -8,6 +8,7 @@ import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, Shape } from
8
8
  import { color, float, uniform, uv } from 'three/tsl';
9
9
  import { MeshBasicNodeMaterial } from 'three/webgpu';
10
10
  import { useShallow } from 'zustand/react/shallow';
11
+ import { owningUnitForZone } from './unit-membership';
11
12
  const Y_OFFSET = 0.01;
12
13
  const WALL_HEIGHT = 2.3;
13
14
  /**
@@ -113,6 +114,10 @@ export const ZoneRenderer = ({ node }) => {
113
114
  return override ? { ...dependency, ...override } : dependency;
114
115
  }), [dependencyIds, dependencyNodes, dependencyOverrides, node]);
115
116
  const polygon = livePolygon ?? proceduralPolygon;
117
+ // The selector returns the unit node itself, so only edits to that unit
118
+ // or its membership re-render this zone.
119
+ const unit = useScene((s) => owningUnitForZone(node, (id) => s.nodes[id]));
120
+ const tintColor = unit?.color ?? node.color;
116
121
  // Create floor shape from polygon
117
122
  const floorShape = useMemo(() => {
118
123
  if (!polygon || polygon.length < 3)
@@ -158,20 +163,20 @@ export const ZoneRenderer = ({ node }) => {
158
163
  }, [polygon]);
159
164
  // Create materials
160
165
  const floorMaterial = useMemo(() => {
161
- if (!node?.color)
166
+ if (!tintColor)
162
167
  return null;
163
- return createFloorMaterial(node.color);
164
- }, [node?.color]);
168
+ return createFloorMaterial(tintColor);
169
+ }, [tintColor]);
165
170
  const wallMaterial = useMemo(() => {
166
- if (!node?.color)
171
+ if (!node.color)
167
172
  return null;
168
173
  return createWallGradientMaterial(node.color);
169
- }, [node?.color]);
174
+ }, [node.color]);
170
175
  const handlers = useNodeEvents(node, 'zone');
171
176
  if (!(node && floorShape && wallGeometry && floorMaterial && wallMaterial)) {
172
177
  return null;
173
178
  }
174
- return (_jsx("group", { ref: ref, ...handlers, userData: { labelPosition: [centroid[0], 1, centroid[1]] }, children: showZones && (_jsxs(_Fragment, { children: [_jsx(Html, { name: "label", position: [centroid[0], 1, centroid[1]], style: { pointerEvents: 'none' }, zIndexRange: [10, 0], children: _jsxs("div", { id: `${node.id}-label`, style: {
179
+ return (_jsx("group", { ref: ref, visible: node.visible !== false, ...handlers, userData: { labelPosition: [centroid[0], 1, centroid[1]] }, children: showZones && (_jsxs(_Fragment, { children: [_jsx(Html, { name: "label", position: [centroid[0], 1, centroid[1]], style: { pointerEvents: 'none' }, zIndexRange: [10, 0], children: _jsxs("div", { id: `${node.id}-label`, style: {
175
180
  display: 'flex',
176
181
  flexDirection: 'column',
177
182
  alignItems: 'center',
@@ -183,7 +188,16 @@ export const ZoneRenderer = ({ node }) => {
183
188
  color: 'white',
184
189
  textShadow: `-1px -1px 0 ${node.color}, 1px -1px 0 ${node.color}, -1px 1px 0 ${node.color}, 1px 1px 0 ${node.color}`,
185
190
  textAlign: 'center',
186
- }, children: _jsx("span", { children: node.name }) }), _jsxs("div", { className: "label-pin", style: {
191
+ }, children: _jsx("span", { children: node.name }) }), unit && (_jsx("div", { style: {
192
+ marginTop: '2px',
193
+ padding: '1px 6px',
194
+ borderRadius: '999px',
195
+ backgroundColor: tintColor,
196
+ color: 'white',
197
+ fontSize: '10px',
198
+ lineHeight: '14px',
199
+ whiteSpace: 'nowrap',
200
+ }, children: unit.name })), _jsxs("div", { className: "label-pin", style: {
187
201
  display: 'flex',
188
202
  flexDirection: 'column',
189
203
  alignItems: 'center',
@@ -0,0 +1,12 @@
1
+ import type { AnyNode, AnyNodeId, UnitNode, ZoneNode } from '@pascal-app/core';
2
+ type ResolveNode = (id: AnyNodeId) => AnyNode | undefined;
3
+ /**
4
+ * Units under the building that owns this zone's level. Units are building
5
+ * children, so this walks that short list instead of scanning every node
6
+ * the way `unitsForZone` does — cheap enough for per-zone store selectors.
7
+ */
8
+ export declare function buildingUnitsForZone(zone: Pick<ZoneNode, 'parentId'>, resolve: ResolveNode): UnitNode[];
9
+ /** The unit whose colour and name a member zone wears: the first one listing it. */
10
+ export declare function owningUnitForZone(zone: Pick<ZoneNode, 'id' | 'parentId'>, resolve: ResolveNode): UnitNode | null;
11
+ export {};
12
+ //# sourceMappingURL=unit-membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-membership.d.ts","sourceRoot":"","sources":["../../src/zone/unit-membership.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAE9E,KAAK,WAAW,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,GAAG,SAAS,CAAA;AAEzD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAChC,OAAO,EAAE,WAAW,GACnB,QAAQ,EAAE,CAUZ;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,UAAU,CAAC,EACvC,OAAO,EAAE,WAAW,GACnB,QAAQ,GAAG,IAAI,CAEjB"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Units under the building that owns this zone's level. Units are building
3
+ * children, so this walks that short list instead of scanning every node
4
+ * the way `unitsForZone` does — cheap enough for per-zone store selectors.
5
+ */
6
+ export function buildingUnitsForZone(zone, resolve) {
7
+ const level = zone.parentId ? resolve(zone.parentId) : undefined;
8
+ const building = level?.parentId ? resolve(level.parentId) : undefined;
9
+ if (building?.type !== 'building')
10
+ return [];
11
+ const units = [];
12
+ for (const childId of building.children) {
13
+ const child = resolve(childId);
14
+ if (child?.type === 'unit')
15
+ units.push(child);
16
+ }
17
+ return units;
18
+ }
19
+ /** The unit whose colour and name a member zone wears: the first one listing it. */
20
+ export function owningUnitForZone(zone, resolve) {
21
+ return buildingUnitsForZone(zone, resolve).find((unit) => unit.members.includes(zone.id)) ?? null;
22
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pascal-app/nodes",
3
- "version": "1.0.0",
4
- "description": "Built-in node bundles for the Pascal 3D editor \u2014 one folder per kind, exported as `builtinPlugin`",
3
+ "version": "1.0.3",
4
+ "description": "Built-in node bundles for the Pascal 3D editor — one folder per kind, exported as `builtinPlugin`",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -10,6 +10,11 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js",
12
12
  "default": "./dist/index.js"
13
+ },
14
+ "./procedural-item": {
15
+ "types": "./dist/procedural-item/index.d.ts",
16
+ "import": "./dist/procedural-item/index.js",
17
+ "default": "./dist/procedural-item/index.js"
13
18
  }
14
19
  },
15
20
  "files": [
@@ -23,9 +28,9 @@
23
28
  "prepublishOnly": "bun run build && bun test"
24
29
  },
25
30
  "peerDependencies": {
26
- "@pascal-app/core": "^1.0.0",
27
- "@pascal-app/editor": "^1.0.0",
28
- "@pascal-app/viewer": "^1.0.0",
31
+ "@pascal-app/core": "^1.0.3",
32
+ "@pascal-app/editor": "^1.0.3",
33
+ "@pascal-app/viewer": "^1.0.3",
29
34
  "@react-three/drei": "^10",
30
35
  "@react-three/fiber": "^9",
31
36
  "lucide-react": "^1",
@@ -35,10 +40,11 @@
35
40
  "zustand": "^5"
36
41
  },
37
42
  "devDependencies": {
38
- "@pascal-app/core": "^1.0.0",
39
- "@pascal-app/editor": "^1.0.0",
40
- "@pascal-app/viewer": "^1.0.0",
43
+ "@pascal-app/core": "^1.0.3",
44
+ "@pascal-app/editor": "^1.0.3",
45
+ "@pascal-app/viewer": "^1.0.3",
41
46
  "@pascal/typescript-config": "*",
47
+ "@react-three/test-renderer": "^9.1.0",
42
48
  "@types/bun": "^1.3.0",
43
49
  "@types/node": "^22.19.12",
44
50
  "@types/react": "^19.2.2",
@@ -54,7 +60,7 @@
54
60
  ],
55
61
  "repository": {
56
62
  "type": "git",
57
- "url": "https://github.com/pascalorg/editor.git",
63
+ "url": "git+https://github.com/pascalorg/editor.git",
58
64
  "directory": "packages/nodes"
59
65
  },
60
66
  "license": "MIT",
@@ -1,16 +0,0 @@
1
- type OpeningDocumentationPatch = {
2
- mark?: string;
3
- constructionType?: 'framed' | 'masonry';
4
- dimensionReference?: 'nominal' | 'rough-opening' | 'masonry-opening' | 'finish-opening';
5
- roughOpeningWidth?: number;
6
- roughOpeningHeight?: number;
7
- masonryOpeningWidth?: number;
8
- masonryOpeningHeight?: number;
9
- finishOpeningWidth?: number;
10
- finishOpeningHeight?: number;
11
- };
12
- export declare function OpeningDocumentationFields({ mark, constructionType, dimensionReference, roughOpeningWidth, roughOpeningHeight, masonryOpeningWidth, masonryOpeningHeight, finishOpeningWidth, finishOpeningHeight, onChange, }: OpeningDocumentationPatch & {
13
- onChange: (patch: OpeningDocumentationPatch) => void;
14
- }): import("react").JSX.Element;
15
- export {};
16
- //# sourceMappingURL=opening-documentation-fields.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"opening-documentation-fields.d.ts","sourceRoot":"","sources":["../../src/shared/opening-documentation-fields.tsx"],"names":[],"mappings":"AAKA,KAAK,yBAAyB,GAAG;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gBAAgB,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IACvC,kBAAkB,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,CAAA;IACvF,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,wBAAgB,0BAA0B,CAAC,EACzC,IAAI,EACJ,gBAA2B,EAC3B,kBAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,QAAQ,GACT,EAAE,yBAAyB,GAAG;IAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,CAAA;CACrD,+BA+GA"}
@@ -1,54 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { getLinearUnitLabel, linearUnitToMeters, metersToLinearUnit } from '@pascal-app/editor';
4
- import { useViewer } from '@pascal-app/viewer';
5
- export function OpeningDocumentationFields({ mark, constructionType = 'framed', dimensionReference = 'nominal', roughOpeningWidth, roughOpeningHeight, masonryOpeningWidth, masonryOpeningHeight, finishOpeningWidth, finishOpeningHeight, onChange, }) {
6
- return (_jsxs("div", { className: "flex flex-col gap-2 px-1 pb-1", children: [_jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Mark" }), _jsx("input", { className: "h-8 rounded-lg border border-border/50 bg-[#2C2C2E] px-2.5 font-mono text-foreground text-xs outline-none transition-colors placeholder:text-muted-foreground/50 focus:border-orange-400/60", defaultValue: mark ?? '', maxLength: 16, onBlur: (event) => {
7
- const next = event.currentTarget.value.trim().toLocaleUpperCase();
8
- if (next !== (mark ?? ''))
9
- onChange({ mark: next || undefined });
10
- }, onKeyDown: (event) => {
11
- if (event.key === 'Enter')
12
- event.currentTarget.blur();
13
- if (event.key === 'Escape') {
14
- event.currentTarget.value = mark ?? '';
15
- event.currentTarget.blur();
16
- }
17
- }, placeholder: "Auto-assigned" }, `mark:${mark ?? ''}`)] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Construction" }), _jsxs("select", { className: "h-8 rounded-lg border border-border/50 bg-[#2C2C2E] px-2 text-foreground text-xs outline-none focus:border-orange-400/60", onChange: (event) => {
18
- const next = event.currentTarget.value;
19
- onChange({
20
- constructionType: next,
21
- dimensionReference: next === 'masonry' && dimensionReference === 'nominal'
22
- ? 'masonry-opening'
23
- : dimensionReference,
24
- });
25
- }, value: constructionType, children: [_jsx("option", { value: "framed", children: "Framed" }), _jsx("option", { value: "masonry", children: "Masonry" })] })] }), _jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Dimension to" }), _jsxs("select", { className: "h-8 rounded-lg border border-border/50 bg-[#2C2C2E] px-2 text-foreground text-xs outline-none focus:border-orange-400/60", onChange: (event) => onChange({
26
- dimensionReference: event.currentTarget
27
- .value,
28
- }), value: dimensionReference, children: [_jsx("option", { value: "nominal", children: "Nominal" }), _jsx("option", { value: "rough-opening", children: "Rough opening" }), _jsx("option", { value: "masonry-opening", children: "Masonry opening" }), _jsx("option", { value: "finish-opening", children: "Finish opening" })] })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(OptionalMeterInput, { label: "RO Width", onChange: (value) => onChange({ roughOpeningWidth: value }), value: roughOpeningWidth }), _jsx(OptionalMeterInput, { label: "RO Height", onChange: (value) => onChange({ roughOpeningHeight: value }), value: roughOpeningHeight })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(OptionalMeterInput, { label: "MO Width", onChange: (value) => onChange({ masonryOpeningWidth: value }), value: masonryOpeningWidth }), _jsx(OptionalMeterInput, { label: "MO Height", onChange: (value) => onChange({ masonryOpeningHeight: value }), value: masonryOpeningHeight })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(OptionalMeterInput, { label: "FO Width", onChange: (value) => onChange({ finishOpeningWidth: value }), value: finishOpeningWidth }), _jsx(OptionalMeterInput, { label: "FO Height", onChange: (value) => onChange({ finishOpeningHeight: value }), value: finishOpeningHeight })] }), _jsx("p", { className: "px-0.5 text-[10px] text-muted-foreground/65 leading-4", children: "Leave RO, MO, and FO values blank until verified by the applicable manufacturer or trade." })] }));
29
- }
30
- function OptionalMeterInput({ label, value, onChange, }) {
31
- const unit = useViewer((state) => state.unit);
32
- const displayValue = value === undefined ? '' : roundForInput(metersToLinearUnit(value, unit));
33
- return (_jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: label }), _jsxs("div", { className: "flex h-8 items-center rounded-lg border border-border/50 bg-[#2C2C2E] focus-within:border-orange-400/60", children: [_jsx("input", { className: "min-w-0 flex-1 bg-transparent px-2 font-mono text-foreground text-xs outline-none placeholder:text-muted-foreground/50", defaultValue: displayValue, min: 0.01, onBlur: (event) => {
34
- const raw = event.currentTarget.value;
35
- if (raw === String(displayValue))
36
- return;
37
- const parsed = Number.parseFloat(raw);
38
- const next = raw === '' || !Number.isFinite(parsed) || parsed <= 0
39
- ? undefined
40
- : linearUnitToMeters(parsed, unit);
41
- if (next !== value)
42
- onChange(next);
43
- }, onKeyDown: (event) => {
44
- if (event.key === 'Enter')
45
- event.currentTarget.blur();
46
- if (event.key === 'Escape') {
47
- event.currentTarget.value = String(displayValue);
48
- event.currentTarget.blur();
49
- }
50
- }, onWheel: (event) => event.currentTarget.blur(), placeholder: "Verify", step: unit === 'imperial' ? 0.01 : 0.001, type: "number" }, `${label}:${displayValue}`), _jsx("span", { className: "pr-2 font-mono text-[10px] text-muted-foreground", children: getLinearUnitLabel(unit) })] })] }));
51
- }
52
- function roundForInput(value) {
53
- return Math.round(value * 1000) / 1000;
54
- }