@pascal-app/editor 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/package.json +18 -15
  2. package/src/components/editor/action-menu-button.tsx +4 -1
  3. package/src/components/editor/alignment-3d-guide-layer.tsx +102 -11
  4. package/src/components/editor/bake-thumbnail.tsx +3 -2
  5. package/src/components/editor/custom-camera-controls.tsx +110 -42
  6. package/src/components/editor/duplicate-node.ts +2 -1
  7. package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
  8. package/src/components/editor/first-person-controls.tsx +77 -68
  9. package/src/components/editor/fit-scene-framing.test.ts +318 -0
  10. package/src/components/editor/fit-scene-framing.ts +142 -0
  11. package/src/components/editor/floating-action-menu.tsx +31 -11
  12. package/src/components/editor/floating-building-action-menu.tsx +1 -1
  13. package/src/components/editor/floor-openings-overlay.tsx +1 -1
  14. package/src/components/editor/floor-region-controls.tsx +2 -2
  15. package/src/components/editor/floorplan-panel.test.ts +220 -0
  16. package/src/components/editor/floorplan-panel.tsx +458 -140
  17. package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
  18. package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
  19. package/src/components/editor/footprint-height-handle.tsx +2 -2
  20. package/src/components/editor/grid.tsx +24 -15
  21. package/src/components/editor/group-actions.ts +19 -1
  22. package/src/components/editor/group-floating-action-menu.tsx +1 -1
  23. package/src/components/editor/group-move-3d.ts +27 -2
  24. package/src/components/editor/group-selection-box-3d.tsx +4 -1
  25. package/src/components/editor/group-transform-shared.ts +23 -1
  26. package/src/components/editor/index.tsx +150 -20
  27. package/src/components/editor/inspector-extension-actions.tsx +36 -0
  28. package/src/components/editor/localized-html.tsx +22 -0
  29. package/src/components/editor/measurement-pill.tsx +1 -1
  30. package/src/components/editor/node-action-menu.tsx +46 -12
  31. package/src/components/editor/node-arrow-handles.tsx +2 -3
  32. package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
  33. package/src/components/editor/open-wall-ends-hint.tsx +1 -1
  34. package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
  35. package/src/components/editor/quick-measurement-card.tsx +1 -1
  36. package/src/components/editor/registry-action-contributions.test.tsx +67 -6
  37. package/src/components/editor/registry-action-contributions.tsx +115 -15
  38. package/src/components/editor/riser-diagram-panel.tsx +59 -9
  39. package/src/components/editor/room-controls.tsx +4 -3
  40. package/src/components/editor/room-handles-2d.tsx +158 -7
  41. package/src/components/editor/room-handles.tsx +244 -54
  42. package/src/components/editor/room-highlight.tsx +2 -0
  43. package/src/components/editor/room-labels.tsx +33 -17
  44. package/src/components/editor/selection-manager.tsx +15 -102
  45. package/src/components/editor/separator-end-grip.tsx +74 -0
  46. package/src/components/editor/site-edge-labels.tsx +7 -3
  47. package/src/components/editor/thumbnail-generator.test.ts +15 -6
  48. package/src/components/editor/thumbnail-generator.tsx +26 -1
  49. package/src/components/editor/use-floorplan-background-placement.ts +55 -52
  50. package/src/components/editor/views/view-bar.tsx +111 -26
  51. package/src/components/editor/wall-measurement-label.tsx +31 -15
  52. package/src/components/editor/wall-move-side-handles.tsx +15 -7
  53. package/src/components/editor/wall-pull-grip.tsx +193 -0
  54. package/src/components/editor/wall-region-handles.tsx +2 -2
  55. package/src/components/editor/wall-snap-beacon-layer.tsx +134 -33
  56. package/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts +76 -0
  57. package/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx +186 -0
  58. package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +63 -3
  59. package/src/components/editor-2d/floorplan-group-move.tsx +32 -4
  60. package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +6 -0
  61. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +33 -24
  62. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +12 -5
  63. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
  64. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +29 -5
  65. package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +96 -4
  66. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +52 -12
  67. package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
  68. package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +13 -1
  69. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
  70. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
  71. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +34 -1
  72. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +211 -39
  73. package/src/components/procedural-items/inspector.tsx +59 -12
  74. package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +2 -0
  75. package/src/components/systems/ceiling/ceiling-system.test.ts +141 -0
  76. package/src/components/systems/ceiling/ceiling-system.tsx +53 -18
  77. package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
  78. package/src/components/systems/roof/roof-edit-system.tsx +30 -19
  79. package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
  80. package/src/components/tools/distribution/distribution-run-tool.tsx +200 -58
  81. package/src/components/tools/item/move-tool.tsx +1 -6
  82. package/src/components/tools/item/placement-history.test.tsx +1 -1
  83. package/src/components/tools/item/placement-strategies.test.ts +64 -1
  84. package/src/components/tools/item/placement-strategies.ts +5 -9
  85. package/src/components/tools/item/use-placement-coordinator.tsx +31 -35
  86. package/src/components/tools/paint-region/wall-paint-region-tool.tsx +1 -1
  87. package/src/components/tools/registry/item-surface-move.test.ts +11 -0
  88. package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
  89. package/src/components/tools/registry/move-registry-node-tool.tsx +38 -14
  90. package/src/components/tools/select/select-candidates.test.ts +45 -0
  91. package/src/components/tools/select/select-candidates.ts +13 -2
  92. package/src/components/tools/shared/cursor-sphere.tsx +10 -3
  93. package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
  94. package/src/components/tools/shared/placement-box.tsx +2 -6
  95. package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
  96. package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
  97. package/src/components/tools/shared/segment-angle.ts +0 -4
  98. package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
  99. package/src/components/tools/tool-manager.tsx +1 -24
  100. package/src/components/tools/wall/wall-drafting.test.ts +299 -23
  101. package/src/components/tools/wall/wall-drafting.ts +132 -24
  102. package/src/components/tools/wall/wall-pull-snap.test.ts +274 -0
  103. package/src/components/tools/wall/wall-pull-snap.ts +563 -0
  104. package/src/components/tools/wall/wall-snap-geometry.test.ts +113 -1
  105. package/src/components/tools/wall/wall-snap-geometry.ts +137 -0
  106. package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
  107. package/src/components/tools/wall/wall-typed-entry.ts +70 -0
  108. package/src/components/tools/zone/zone-tool.tsx +3 -3
  109. package/src/components/ui/action-menu/action-button.tsx +2 -0
  110. package/src/components/ui/action-menu/camera-actions.tsx +8 -7
  111. package/src/components/ui/action-menu/control-modes.tsx +9 -5
  112. package/src/components/ui/action-menu/follow-pascal-pill.tsx +3 -1
  113. package/src/components/ui/action-menu/follow-pascal-toggle.tsx +7 -1
  114. package/src/components/ui/action-menu/furnish-tools.tsx +7 -6
  115. package/src/components/ui/action-menu/index.tsx +1 -0
  116. package/src/components/ui/action-menu/measurement-control.tsx +35 -29
  117. package/src/components/ui/action-menu/point-ask-button.tsx +4 -3
  118. package/src/components/ui/action-menu/structure-tools.tsx +25 -23
  119. package/src/components/ui/action-menu/view-toggles.test.ts +18 -0
  120. package/src/components/ui/action-menu/view-toggles.tsx +256 -51
  121. package/src/components/ui/build-panel/build-panel.tsx +163 -25
  122. package/src/components/ui/command-palette/editor-commands.tsx +38 -11
  123. package/src/components/ui/controls/finish-swatch.tsx +45 -19
  124. package/src/components/ui/controls/material-picker.tsx +24 -17
  125. package/src/components/ui/controls/metric-control.test.ts +52 -0
  126. package/src/components/ui/controls/metric-control.tsx +62 -24
  127. package/src/components/ui/controls/segmented-control.tsx +5 -2
  128. package/src/components/ui/controls/slider-control.test.tsx +23 -0
  129. package/src/components/ui/controls/slider-control.tsx +47 -19
  130. package/src/components/ui/controls/tool-options-panel.tsx +74 -44
  131. package/src/components/ui/floating-level-selector.tsx +100 -48
  132. package/src/components/ui/helpers/building-helper.tsx +5 -3
  133. package/src/components/ui/helpers/contextual-helper-panel.tsx +97 -37
  134. package/src/components/ui/helpers/helper-manager.test.tsx +106 -3
  135. package/src/components/ui/helpers/helper-manager.tsx +136 -57
  136. package/src/components/ui/helpers/item-helper.tsx +6 -4
  137. package/src/components/ui/helpers/registered-tool-helper.tsx +3 -1
  138. package/src/components/ui/level-duplicate-dialog.tsx +32 -23
  139. package/src/components/ui/level-wall-copy-prompt.tsx +124 -0
  140. package/src/components/ui/panels/collections/collections-popover.tsx +11 -11
  141. package/src/components/ui/panels/deck-boards-fields.tsx +136 -0
  142. package/src/components/ui/panels/floor-foundation-panel.tsx +114 -39
  143. package/src/components/ui/panels/floor-opening-panel.tsx +74 -26
  144. package/src/components/ui/panels/inspector-extensions.tsx +66 -0
  145. package/src/components/ui/panels/mobile-panel-sheet.tsx +3 -1
  146. package/src/components/ui/panels/mobile-selection-bar.tsx +34 -28
  147. package/src/components/ui/panels/multi-field-value.test.ts +27 -0
  148. package/src/components/ui/panels/multi-field-value.ts +20 -1
  149. package/src/components/ui/panels/multi-height-mode.tsx +11 -10
  150. package/src/components/ui/panels/multi-parametric-inspector.tsx +122 -34
  151. package/src/components/ui/panels/multi-selection-panel.tsx +76 -36
  152. package/src/components/ui/panels/node-display.ts +35 -24
  153. package/src/components/ui/panels/panel-manager.tsx +9 -5
  154. package/src/components/ui/panels/panel-wrapper.tsx +63 -127
  155. package/src/components/ui/panels/parametric-field-control.tsx +13 -10
  156. package/src/components/ui/panels/parametric-inspector.tsx +18 -12
  157. package/src/components/ui/panels/reference-panel.tsx +51 -35
  158. package/src/components/ui/panels/room-construction-rows.tsx +465 -66
  159. package/src/components/ui/panels/room-name-options.test.ts +36 -3
  160. package/src/components/ui/panels/room-name-options.ts +110 -11
  161. package/src/components/ui/panels/room-openings-field.tsx +22 -13
  162. package/src/components/ui/panels/room-panel.tsx +207 -100
  163. package/src/components/ui/panels/shape-choice.tsx +7 -5
  164. package/src/components/ui/panels/wall-region-list.tsx +7 -7
  165. package/src/components/ui/primitives/shortcut-token.tsx +10 -6
  166. package/src/components/ui/right-stack.test.ts +13 -6
  167. package/src/components/ui/right-stack.tsx +21 -10
  168. package/src/components/ui/sidebar/icon-rail.tsx +11 -9
  169. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +10 -10
  170. package/src/components/ui/sidebar/panels/items-panel/index.tsx +10 -9
  171. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +3 -0
  172. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +102 -32
  173. package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +1 -5
  174. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +4 -3
  175. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +5 -3
  176. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +4 -2
  177. package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +7 -5
  178. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +4 -2
  179. package/src/components/ui/sidebar/panels/site-panel/default-names.ts +75 -0
  180. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +4 -2
  181. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +4 -2
  182. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +4 -2
  183. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +4 -2
  184. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +4 -2
  185. package/src/components/ui/sidebar/panels/site-panel/index.tsx +118 -72
  186. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +36 -3
  187. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +4 -2
  188. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +7 -4
  189. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +8 -2
  190. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +8 -5
  191. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +4 -2
  192. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +9 -4
  193. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +4 -2
  194. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +4 -2
  195. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +8 -7
  196. package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +7 -6
  197. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +16 -1
  198. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +15 -8
  199. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +4 -2
  200. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +4 -2
  201. package/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +3 -1
  202. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +19 -9
  203. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +25 -14
  204. package/src/components/ui/sidebar/tab-bar.tsx +4 -1
  205. package/src/components/ui/sidebar/use-plugin-panels.tsx +19 -10
  206. package/src/components/ui/snap-target-badge.tsx +7 -6
  207. package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +721 -0
  208. package/src/components/ui/wall-type/wall-type-menu.tsx +167 -0
  209. package/src/components/viewer/floorplan-compass-button.tsx +12 -3
  210. package/src/components/viewer/floorplan-preview.tsx +27 -19
  211. package/src/components/viewer/render-settings-menu.tsx +294 -0
  212. package/src/components/viewer/sky-control.tsx +710 -0
  213. package/src/components/viewer/use-viewer-ui-sounds.test.ts +15 -0
  214. package/src/components/viewer/use-viewer-ui-sounds.ts +46 -0
  215. package/src/components/viewer/viewer-controls-bar.tsx +278 -260
  216. package/src/components/viewer/viewer-hover-label.tsx +12 -4
  217. package/src/components/viewer/viewer-rooms.tsx +62 -5
  218. package/src/components/viewer/viewer-scene-header.tsx +28 -17
  219. package/src/components/viewer/viewer-stage-switcher.tsx +4 -2
  220. package/src/components/viewer-overlay.tsx +8 -0
  221. package/src/components/walkthrough-hud.tsx +75 -2
  222. package/src/hooks/use-keyboard.test.ts +85 -4
  223. package/src/hooks/use-keyboard.ts +65 -7
  224. package/src/hooks/use-selected-room.ts +12 -1
  225. package/src/i18n/floor-footprint-name.ts +30 -0
  226. package/src/i18n/level-name.ts +39 -0
  227. package/src/i18n/locales/en/messages.po +15849 -0
  228. package/src/i18n/locales/en/messages.ts +1 -0
  229. package/src/i18n/locales/en-XA/messages.ts +1 -0
  230. package/src/i18n/locales/es/messages.po +39331 -0
  231. package/src/i18n/locales/es/messages.ts +1 -0
  232. package/src/i18n/locales/fr/messages.po +39331 -0
  233. package/src/i18n/locales/fr/messages.ts +1 -0
  234. package/src/i18n/locales/ja/messages.po +39331 -0
  235. package/src/i18n/locales/ja/messages.ts +1 -0
  236. package/src/i18n/locales/zh-CN/messages.po +39331 -0
  237. package/src/i18n/locales/zh-CN/messages.ts +1 -0
  238. package/src/i18n/locales.test.ts +63 -0
  239. package/src/i18n/locales.ts +32 -0
  240. package/src/i18n/message-slot.tsx +25 -0
  241. package/src/i18n/node-messages.ts +169 -0
  242. package/src/i18n/pseudo-locale.ts +17 -0
  243. package/src/i18n/published-entry.test.ts +17 -0
  244. package/src/i18n/scene-theme-name.ts +16 -0
  245. package/src/index.tsx +224 -45
  246. package/src/lib/add-storey.test.ts +3 -3
  247. package/src/lib/contextual-help.test.ts +20 -1
  248. package/src/lib/contextual-help.ts +101 -19
  249. package/src/lib/continuation.ts +38 -11
  250. package/src/lib/elevation-guides.ts +21 -6
  251. package/src/lib/elevator-support.ts +1 -72
  252. package/src/lib/floor-footprints.test.ts +3 -2
  253. package/src/lib/floor-footprints.ts +1 -9
  254. package/src/lib/floor-foundation-support.test.ts +15 -6
  255. package/src/lib/floor-opening-draft.ts +1 -1
  256. package/src/lib/floor-region-session.ts +1 -1
  257. package/src/lib/floorplan/dimension-drive.test.ts +36 -2
  258. package/src/lib/floorplan/dimension-drive.ts +68 -3
  259. package/src/lib/floorplan/floorplan-export.test.ts +16 -5
  260. package/src/lib/floorplan/floorplan-export.tsx +13 -16
  261. package/src/lib/floorplan/floorplan-extension.test.ts +11 -12
  262. package/src/lib/floorplan/floorplan-extension.ts +37 -18
  263. package/src/lib/floorplan/floorplan-mode.test.ts +13 -6
  264. package/src/lib/floorplan/floorplan-mode.ts +14 -12
  265. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +1 -1
  266. package/src/lib/floorplan/floorplan-readonly.ts +3 -3
  267. package/src/lib/floorplan/open-wall-ends.ts +2 -1
  268. package/src/lib/floorplan/schedules.ts +10 -6
  269. package/src/lib/floorplan/site-plan/site-annotations.test.ts +46 -1
  270. package/src/lib/floorplan/site-plan/site-annotations.ts +3 -0
  271. package/src/lib/floorplan/site-plan/site-parts.ts +6 -3
  272. package/src/lib/geometry-script/author.test.ts +114 -0
  273. package/src/lib/geometry-script/author.ts +55 -23
  274. package/src/lib/geometry-script/client.ts +3 -0
  275. package/src/lib/geometry-script/finish-scripts.ts +7 -7
  276. package/src/lib/gesture-lifecycle.ts +3 -1
  277. package/src/lib/glb-export.test.ts +327 -0
  278. package/src/lib/glb-export.ts +70 -2
  279. package/src/lib/grid-frame.test.ts +56 -3
  280. package/src/lib/grid-frame.ts +28 -1
  281. package/src/lib/history.test.ts +2 -1
  282. package/src/lib/hud-title.ts +48 -24
  283. package/src/lib/ifc-export.test.ts +41 -1
  284. package/src/lib/inspector-card-mode.test.ts +3 -31
  285. package/src/lib/inspector-card-mode.ts +5 -10
  286. package/src/lib/inspector-expanded.test.ts +13 -0
  287. package/src/lib/inspector-expanded.ts +13 -1
  288. package/src/lib/interaction/scope.ts +1 -0
  289. package/src/lib/keyboard-pan.test.ts +7 -0
  290. package/src/lib/keyboard-pan.ts +9 -2
  291. package/src/lib/layer-thickness.test.ts +22 -0
  292. package/src/lib/layer-thickness.ts +79 -0
  293. package/src/lib/level-selection.test.ts +18 -2
  294. package/src/lib/level-selection.ts +31 -8
  295. package/src/lib/linear-display.ts +1 -1
  296. package/src/lib/live-gesture-round-trip.test.ts +1 -1
  297. package/src/lib/lot/drop-in.test.ts +59 -1
  298. package/src/lib/lot/drop-in.ts +42 -50
  299. package/src/lib/material-swatch-style.ts +24 -0
  300. package/src/lib/measurement-label.test.ts +1 -1
  301. package/src/lib/measurement-parser.ts +7 -3
  302. package/src/lib/measurements.test.ts +24 -6
  303. package/src/lib/measurements.ts +1 -203
  304. package/src/lib/mezzanine-selection.test.ts +3 -1
  305. package/src/lib/node-action-movement.test.tsx +115 -0
  306. package/src/lib/node-action-movement.ts +2 -0
  307. package/src/lib/orbit-near-plane.test.ts +12 -0
  308. package/src/lib/orbit-near-plane.ts +13 -0
  309. package/src/lib/paint-regions.test.ts +8 -5
  310. package/src/lib/paint-scope.test.ts +53 -0
  311. package/src/lib/paint-scope.ts +18 -4
  312. package/src/lib/panel-rows.ts +17 -8
  313. package/src/lib/placement-metadata.ts +4 -0
  314. package/src/lib/point-ask/describe-target.ts +6 -8
  315. package/src/lib/point-ask/region.ts +1 -1
  316. package/src/lib/print-shell-compiler.ts +12 -1
  317. package/src/lib/print-wall-solids.test.ts +11 -0
  318. package/src/lib/print-wall-solids.ts +9 -0
  319. package/src/lib/reference-scale.ts +83 -0
  320. package/src/lib/room-assembly-overlay.ts +1 -1
  321. package/src/lib/room-built-on.test.ts +28 -17
  322. package/src/lib/room-built-on.ts +21 -17
  323. package/src/lib/room-construction-commands.ts +3 -2
  324. package/src/lib/room-construction.test.ts +28 -1
  325. package/src/lib/room-construction.ts +14 -0
  326. package/src/lib/room-controls-phase6.test.ts +141 -1
  327. package/src/lib/room-handle-drag.ts +554 -58
  328. package/src/lib/room-name-catalog.test.ts +8 -0
  329. package/src/lib/room-name-catalog.ts +8 -1
  330. package/src/lib/room-name-messages.test.ts +132 -0
  331. package/src/lib/room-name-messages.ts +147 -0
  332. package/src/lib/room-name-storage.test.ts +334 -0
  333. package/src/lib/room-push-dimensions.test.ts +38 -1
  334. package/src/lib/room-push-dimensions.ts +226 -2
  335. package/src/lib/room-selection.test.ts +23 -6
  336. package/src/lib/scene-bounds.test.ts +144 -0
  337. package/src/lib/scene-bounds.ts +79 -15
  338. package/src/lib/scene-clipboard.test.ts +70 -49
  339. package/src/lib/scene-clipboard.ts +11 -5
  340. package/src/lib/selection-cycle.ts +63 -0
  341. package/src/lib/separator-edit.test.ts +431 -0
  342. package/src/lib/separator-edit.ts +179 -0
  343. package/src/lib/separator-lines.ts +38 -0
  344. package/src/lib/sfx-bus.ts +27 -1
  345. package/src/lib/sfx-player.ts +16 -0
  346. package/src/lib/snapping-mode.test.ts +23 -1
  347. package/src/lib/tool-cursor-icon.ts +5 -1
  348. package/src/lib/tool-shortcuts.ts +130 -0
  349. package/src/lib/viewer-selection.test.ts +28 -24
  350. package/src/lib/viewer-selection.ts +21 -6
  351. package/src/lib/wall-draw-variant.test.ts +7 -6
  352. package/src/lib/wall-draw-variant.ts +107 -6
  353. package/src/lib/wall-nudge.test.ts +44 -0
  354. package/src/lib/wall-nudge.ts +131 -0
  355. package/src/lib/wall-parallel-snap.test.ts +83 -0
  356. package/src/lib/wall-parallel-snap.ts +176 -0
  357. package/src/lib/wall-placement-pointer.test.ts +23 -0
  358. package/src/lib/wall-placement-pointer.ts +18 -0
  359. package/src/lib/wall-pull.test.ts +245 -0
  360. package/src/lib/wall-pull.ts +209 -0
  361. package/src/lib/wall-push-line-up.test.ts +132 -0
  362. package/src/lib/wall-region-list.ts +17 -6
  363. package/src/lib/wall-run-snap.test.ts +188 -0
  364. package/src/lib/wall-run-snap.ts +83 -0
  365. package/src/lib/wall-type.test.ts +125 -0
  366. package/src/lib/wall-type.ts +119 -0
  367. package/src/lib/window-interaction.test.ts +44 -0
  368. package/src/lib/world-grid-snap.test.ts +139 -2
  369. package/src/lib/world-grid-snap.ts +102 -105
  370. package/src/store/use-alignment-guides.ts +27 -1
  371. package/src/store/use-editor.tsx +53 -0
  372. package/src/store/use-floorplan-annotation-visibility.test.ts +64 -0
  373. package/src/store/use-floorplan-annotation-visibility.ts +47 -22
  374. package/src/store/use-placement-typing.test.ts +165 -0
  375. package/src/store/use-placement-typing.ts +186 -0
  376. package/src/store/use-wall-snap-indicator.ts +15 -2
  377. package/src/components/tools/elevator/elevator-defaults.ts +0 -8
  378. package/src/components/tools/elevator/elevator-tool.tsx +0 -372
  379. package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
  380. package/src/lib/door-interaction.ts +0 -102
  381. package/src/lib/measurement-label.ts +0 -68
  382. package/src/lib/window-interaction.ts +0 -100
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type AnyNode,
3
3
  type AnyNodeId,
4
+ doorPositionForFacing,
4
5
  emitter,
5
6
  nodeRegistry,
6
7
  pauseSpaceDetection,
@@ -34,12 +35,15 @@ import { isActive } from '../lib/interaction/scope'
34
35
  import { paintRegionModeActive } from '../lib/paint-region-mode'
35
36
  import { popRoomSelection } from '../lib/room-selection-commands'
36
37
  import { copySelectedNodesToEditorClipboard } from '../lib/scene-clipboard'
38
+ import { cycleSelectionAtPointer, trackSelectionCyclePointer } from '../lib/selection-cycle'
37
39
  import { sfxEmitter } from '../lib/sfx-bus'
38
40
  import { openSidebarPanel } from '../lib/sidebar-panel'
39
41
  import { activeSiteNode, clampBrushRadius } from '../lib/terrain-sculpt'
42
+ import { armToolShortcut, toolShortcutForKey } from '../lib/tool-shortcuts'
40
43
  import { isTypingTarget } from '../lib/typing-target'
41
44
  import { leaveUnitFocus } from '../lib/units'
42
- import { selectWallDrawVariant } from '../lib/wall-draw-variant'
45
+ import { subscribeWallKindReset } from '../lib/wall-draw-variant'
46
+ import { isWallNudgeKey, nudgeSelectedWall } from '../lib/wall-nudge'
43
47
  import useDeleteConfirmation from '../store/use-delete-confirmation'
44
48
  import useEditor, { getActiveContinuationContext, getActiveSnapContext } from '../store/use-editor'
45
49
  import useInteractionScope, {
@@ -49,6 +53,14 @@ import useInteractionScope, {
49
53
  import { groupCurrentSelection, ungroupCurrentSelection } from '../store/use-session-groups'
50
54
  import { activeViewLayout } from '../store/view-layout'
51
55
 
56
+ const pickKeyFields = (e: KeyboardEvent) => ({
57
+ code: e.code,
58
+ shiftKey: e.shiftKey,
59
+ metaKey: e.metaKey,
60
+ ctrlKey: e.ctrlKey,
61
+ altKey: e.altKey,
62
+ })
63
+
52
64
  export function hasSceneKeyboardFocus(): boolean {
53
65
  const layout = activeViewLayout(useEditor.getState())
54
66
  return isSceneView(layout.panes[layout.focus])
@@ -208,13 +220,12 @@ export const runHistoryShortcut = (direction: 'undo' | 'redo') => {
208
220
  }
209
221
 
210
222
  /**
211
- * B: the wall tool on Rectangle — the quickest room — with the Build panel
212
- * showing, so the lit tile says what is in hand. The panel's tiles still pick
213
- * another shape for the session. The panel opens before the tool is armed: a
214
- * host may drop the armed tool when the panel changes.
223
+ * B: the wall tool on the Rooms shape picked last (Rectangle, Polygon or Walls,
224
+ * kept with the editor preferences; Rectangle until one is picked), with the
225
+ * Build panel showing, so the lit tile says what is in hand. The panel opens
226
+ * before the tool is armed: a host may drop the armed tool when the panel changes.
215
227
  */
216
228
  export const armWallToolFromShortcut = () => {
217
- selectWallDrawVariant('rectangle')
218
229
  openSidebarPanel(['build'])
219
230
  useEditor.getState().armToolMode({ mode: 'build', tool: 'wall' })
220
231
  }
@@ -257,6 +268,8 @@ export const isToolOwnedRotation = () => {
257
268
  (editor.tool === 'door' ||
258
269
  editor.tool === 'window' ||
259
270
  editor.tool === 'roof' ||
271
+ editor.tool === 'stair' ||
272
+ editor.tool === 'elevator' ||
260
273
  // The item tool is mounted for the build mode, but it only owns R/T
261
274
  // when a catalog item is actually selected and a placement draft can
262
275
  // exist. Without this check, selecting an existing item in the 2D plan
@@ -312,6 +325,7 @@ export const useKeyboard = ({
312
325
  if (disabled) {
313
326
  return
314
327
  }
328
+ trackSelectionCyclePointer()
315
329
 
316
330
  // True while an active placement tool owns R/T. Door/window tools flip the
317
331
  // draft, item / lean-to placement rotates its draft, and the roof tool turns
@@ -467,6 +481,18 @@ export const useKeyboard = ({
467
481
  }
468
482
  }
469
483
 
484
+ // Drafting tools on Shift with D / W / S / R, where the bare key pans or
485
+ // rotates (lib/tool-shortcuts). An armed placement keeps Shift+R as its own R.
486
+ const toolShortcut = isVersionPreviewMode
487
+ ? null
488
+ : toolShortcutForKey({ ...pickKeyFields(e), repeat: false })
489
+ if (toolShortcut && !(toolShortcut === 'roof' && isToolOwnedRotation())) {
490
+ e.preventDefault()
491
+ // A held chord repeats: arm once, and never let a repeat fall through to bare R.
492
+ if (!e.repeat) armToolShortcut(toolShortcut)
493
+ return
494
+ }
495
+
470
496
  if (e.key === 'Escape') {
471
497
  e.preventDefault()
472
498
 
@@ -585,6 +611,31 @@ export const useKeyboard = ({
585
611
  }
586
612
  }
587
613
  }
614
+ } else if (isWallNudgeKey(e.key) && !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) {
615
+ // Bare arrows nudge a selected wall an inch in the floor plan.
616
+ const editor = useEditor.getState()
617
+ if (
618
+ isVersionPreviewMode ||
619
+ editor.mode !== 'select' ||
620
+ useInteractionScope.getState().scope.kind !== 'idle' ||
621
+ editor.isFirstPersonMode
622
+ ) {
623
+ return
624
+ }
625
+ if (nudgeSelectedWall(e.key)) e.preventDefault()
626
+ } else if (e.key === 'Tab' && !e.metaKey && !e.ctrlKey && !e.altKey) {
627
+ // Tab steps the selection to the next object under the pointer in the
628
+ // floor plan (Shift+Tab back): a wall hidden under another is reachable.
629
+ const editor = useEditor.getState()
630
+ if (
631
+ isVersionPreviewMode ||
632
+ editor.mode !== 'select' ||
633
+ useInteractionScope.getState().scope.kind !== 'idle' ||
634
+ editor.isFirstPersonMode
635
+ ) {
636
+ return
637
+ }
638
+ if (cycleSelectionAtPointer(e.shiftKey)) e.preventDefault()
588
639
  } else if (
589
640
  (e.key === 'r' || e.key === 'R') &&
590
641
  !e.metaKey &&
@@ -600,7 +651,7 @@ export const useKeyboard = ({
600
651
  // open/close toggle lives on E. Windows still use R to toggle
601
652
  // their open/closed state.
602
653
  //
603
- // Skipped while an item, door, window, or roof placement owns rotation.
654
+ // Skipped while a placement tool (item, door, window, roof, stair…) owns rotation.
604
655
  // The user can still have a node selected during placement; without this
605
656
  // guard both the draft and the selection would rotate.
606
657
  //
@@ -637,6 +688,11 @@ export const useKeyboard = ({
637
688
  useScene.getState().updateNode(node.id, {
638
689
  side: node.side === 'front' ? 'back' : 'front',
639
690
  rotation: [node.rotation[0], node.rotation[1] + Math.PI, node.rotation[2]],
691
+ position: doorPositionForFacing(node, [
692
+ node.rotation[0],
693
+ node.rotation[1] + Math.PI,
694
+ node.rotation[2],
695
+ ]),
640
696
  })
641
697
  if (node.parentId) {
642
698
  useScene.getState().dirtyNodes.add(node.parentId as AnyNodeId)
@@ -847,7 +903,9 @@ export const useKeyboard = ({
847
903
  window.addEventListener('keydown', handleSessionGroupKeyDown, true)
848
904
  window.addEventListener('keydown', handleKeyDown)
849
905
  window.addEventListener('keyup', handleKeyUp)
906
+ const unsubscribeWallKind = subscribeWallKindReset()
850
907
  return () => {
908
+ unsubscribeWallKind()
851
909
  window.removeEventListener('keydown', handleSessionGroupKeyDown, true)
852
910
  window.removeEventListener('keydown', handleKeyDown)
853
911
  window.removeEventListener('keyup', handleKeyUp)
@@ -1,8 +1,9 @@
1
1
  'use client'
2
2
 
3
- import { type AnyNode, type AnyNodeId, useScene } from '@pascal-app/core'
3
+ import { type AnyNode, type AnyNodeId, nodeRegistry, useScene } from '@pascal-app/core'
4
4
  import { useViewer } from '@pascal-app/viewer'
5
5
  import { useCallback, useSyncExternalStore } from 'react'
6
+ import { getFloorplanNodeExtension } from '../lib/floorplan/floorplan-extension'
6
7
  import { selectionEnabled } from '../lib/interaction/scope'
7
8
  import {
8
9
  type RoomKey,
@@ -134,8 +135,18 @@ export function hoverRoomFromHit(
134
135
  return !!room
135
136
  }
136
137
 
138
+ /**
139
+ * The room a plan hit picks first. A kind whose plan extension declares
140
+ * `planHitSelectsNode` (a wall: a thin band between two rooms whose interiors
141
+ * are clickable in their own right) keeps the hit: picking a room by which
142
+ * half of the band the pointer landed on made thin partitions take several
143
+ * clicks. 3D keeps them room-first, where a room's floor is often hidden
144
+ * behind its walls.
145
+ */
137
146
  export function resolvePlanRoomHit(nodeId: string | null, point: readonly [number, number]) {
138
147
  const node = nodeId ? useScene.getState().nodes[nodeId as AnyNodeId] : null
148
+ if (node && getFloorplanNodeExtension(nodeRegistry.get(node.type))?.planHitSelectsNode)
149
+ return null
139
150
  const levelId = node?.parentId ?? useViewer.getState().selection.levelId
140
151
  return levelId ? resolveEditorRoomHit(node ?? null, levelId, point, '2d') : null
141
152
  }
@@ -0,0 +1,30 @@
1
+ import {
2
+ type AnyNode,
3
+ floorFootprintNaming,
4
+ type PascalI18n,
5
+ type SlabNode,
6
+ } from '@pascal-app/core'
7
+ import { displayRoomName } from '../lib/room-name-messages'
8
+
9
+ /** `floorFootprintName` in the UI language; MCP and agents keep core's English. */
10
+ export function localizedFloorFootprintName(
11
+ nodes: Readonly<Record<string, AnyNode>>,
12
+ plate: SlabNode,
13
+ i18n: PascalI18n,
14
+ ): string {
15
+ const naming = floorFootprintNaming(nodes, plate)
16
+ switch (naming.kind) {
17
+ case 'named':
18
+ return naming.name
19
+ case 'room':
20
+ return i18n._({
21
+ id: 'editor.floorFootprint.room',
22
+ message: '{room} floor',
23
+ values: { room: displayRoomName(naming.room, i18n) },
24
+ })
25
+ case 'shared':
26
+ return i18n._({ id: 'editor.floorFootprint.shared', message: 'Shared floor' })
27
+ case 'area':
28
+ return i18n._({ id: 'editor.floorFootprint.area', message: 'Floor area' })
29
+ }
30
+ }
@@ -0,0 +1,39 @@
1
+ import { getDefaultLevelName, levelDisplayNumber, type PascalI18n } from '@pascal-app/core'
2
+
3
+ type DisplayLevel = {
4
+ level?: number
5
+ name?: string
6
+ }
7
+
8
+ /** The level's own name, or undefined while it carries a generated default. */
9
+ export function authoredLevelName(level: DisplayLevel): string | undefined {
10
+ const levelNumber = level.level ?? 0
11
+ const name = level.name?.trim()
12
+ return name && name !== `Level ${levelNumber}` && name !== getDefaultLevelName(levelNumber)
13
+ ? name
14
+ : undefined
15
+ }
16
+
17
+ export function localizedLevelName(level: DisplayLevel, i18n: PascalI18n, locale: string): string {
18
+ const levelNumber = level.level ?? 0
19
+ const authoredName = authoredLevelName(level)
20
+ if (authoredName) return authoredName
21
+ if (levelNumber === 0) {
22
+ return i18n._({ id: 'core.level.groundFloor', message: 'Ground floor' })
23
+ }
24
+ if (levelNumber === -1) {
25
+ return i18n._({ id: 'core.level.basement', message: 'Basement' })
26
+ }
27
+ if (levelNumber < -1) {
28
+ return i18n._({
29
+ id: 'core.level.basementNumber',
30
+ message: 'Basement {number}',
31
+ values: { number: -levelNumber },
32
+ })
33
+ }
34
+ return i18n._({
35
+ id: 'core.level.floorNumber',
36
+ message: 'Floor {number}',
37
+ values: { number: levelDisplayNumber(levelNumber, locale) },
38
+ })
39
+ }