@pascal-app/editor 0.8.0 → 0.9.2

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 (350) hide show
  1. package/package.json +15 -13
  2. package/src/components/editor/alignment-3d-guide-layer.tsx +168 -0
  3. package/src/components/editor/bake-exporter.tsx +47 -0
  4. package/src/components/editor/custom-camera-controls.tsx +795 -28
  5. package/src/components/editor/editor-layout-mobile.tsx +8 -3
  6. package/src/components/editor/editor-layout-v2.tsx +76 -51
  7. package/src/components/editor/export-manager.tsx +69 -32
  8. package/src/components/editor/fence-tangent-lines-3d.tsx +87 -0
  9. package/src/components/editor/first-person/build-collider-world.test.ts +182 -0
  10. package/src/components/editor/first-person/build-collider-world.ts +228 -83
  11. package/src/components/editor/first-person-controls.tsx +943 -27
  12. package/src/components/editor/floating-action-menu.tsx +676 -208
  13. package/src/components/editor/floating-building-action-menu.tsx +2 -2
  14. package/src/components/editor/floorplan-background-selection.test.ts +58 -0
  15. package/src/components/editor/floorplan-background-selection.ts +3 -2
  16. package/src/components/editor/floorplan-panel.tsx +6916 -12137
  17. package/src/components/editor/grid.tsx +197 -36
  18. package/src/components/editor/group-actions.ts +457 -0
  19. package/src/components/editor/group-floating-action-menu.tsx +130 -0
  20. package/src/components/editor/group-move-3d.ts +397 -0
  21. package/src/components/editor/group-rotate-handle.tsx +420 -0
  22. package/src/components/editor/group-selection-box-3d.tsx +173 -0
  23. package/src/components/editor/group-transform-shared.test.ts +396 -0
  24. package/src/components/editor/group-transform-shared.ts +489 -0
  25. package/src/components/editor/handles/handle-arrow.tsx +581 -0
  26. package/src/components/editor/handles/use-handle-drag.ts +246 -0
  27. package/src/components/editor/index.tsx +412 -162
  28. package/src/components/editor/measurement-pill.tsx +115 -0
  29. package/src/components/editor/node-action-menu.tsx +14 -1
  30. package/src/components/editor/node-arrow-handles.tsx +1646 -0
  31. package/src/components/editor/opening-guides-3d-layer.tsx +144 -0
  32. package/src/components/editor/quick-measurement-card.tsx +70 -0
  33. package/src/components/editor/quick-measurement-hud.tsx +28 -0
  34. package/src/components/editor/riser-diagram-panel.tsx +137 -0
  35. package/src/components/editor/selection-manager.tsx +1106 -483
  36. package/src/components/editor/site-edge-labels.tsx +45 -21
  37. package/src/components/editor/slab-hole-highlights.tsx +474 -0
  38. package/src/components/editor/snapshot-capture-overlay.tsx +369 -155
  39. package/src/components/editor/three-context-bridge.ts +22 -0
  40. package/src/components/editor/thumbnail-generator.tsx +140 -41
  41. package/src/components/editor/use-floorplan-background-placement.ts +190 -35
  42. package/src/components/editor/use-floorplan-hit-testing.ts +24 -0
  43. package/src/components/editor/use-floorplan-scene-data.ts +19 -7
  44. package/src/components/editor/use-mesh-settle-epoch.ts +26 -0
  45. package/src/components/editor/wall-measurement-label.tsx +14 -19
  46. package/src/components/editor/wall-move-side-handles.tsx +870 -0
  47. package/src/components/editor/wall-opening-highlights.tsx +181 -0
  48. package/src/components/editor/wall-snap-beacon-layer.tsx +304 -0
  49. package/src/components/editor-2d/floorplan-action-menu-layer.tsx +15 -6
  50. package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +142 -0
  51. package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +5 -3
  52. package/src/components/editor-2d/floorplan-group-action-menu.tsx +87 -0
  53. package/src/components/editor-2d/floorplan-group-move.tsx +701 -0
  54. package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +113 -0
  55. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1656 -0
  56. package/src/components/editor-2d/floorplan-quick-measure-layer.tsx +212 -0
  57. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +392 -0
  58. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +857 -0
  59. package/src/components/editor-2d/floorplan-render-context.tsx +62 -0
  60. package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +77 -0
  61. package/src/components/editor-2d/floorplan-wall-move-ghost-layer.tsx +47 -0
  62. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +266 -0
  63. package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +15 -0
  64. package/src/components/editor-2d/renderers/floorplan-label-angle.ts +14 -0
  65. package/src/components/editor-2d/renderers/floorplan-measurements-layer.tsx +108 -66
  66. package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +62 -0
  67. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +308 -0
  68. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +3325 -0
  69. package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +24 -9
  70. package/src/components/editor-2d/renderers/floorplan-voronoi-layer.tsx +128 -0
  71. package/src/components/editor-2d/svg-paths.ts +10 -2
  72. package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +439 -57
  73. package/src/components/systems/ceiling/ceiling-system.tsx +109 -12
  74. package/src/components/systems/roof/roof-edit-system.tsx +1851 -22
  75. package/src/components/systems/selection-affordance-manager.tsx +38 -0
  76. package/src/components/systems/stair/stair-edit-system.tsx +1 -1
  77. package/src/components/systems/zone/zone-label-editor-system.tsx +14 -1
  78. package/src/components/systems/zone/zone-system.tsx +42 -13
  79. package/src/components/tools/elevator/elevator-defaults.ts +8 -0
  80. package/src/components/tools/elevator/elevator-tool.tsx +375 -0
  81. package/src/components/tools/elevator/move-elevator-tool.tsx +263 -0
  82. package/src/components/tools/fence/fence-drafting.ts +141 -27
  83. package/src/components/tools/item/move-tool.tsx +45 -105
  84. package/src/components/tools/item/placement-math.test.ts +22 -0
  85. package/src/components/tools/item/placement-math.ts +59 -7
  86. package/src/components/tools/item/placement-strategies.ts +432 -16
  87. package/src/components/tools/item/placement-types.ts +22 -1
  88. package/src/components/tools/item/use-draft-node.ts +51 -2
  89. package/src/components/tools/item/use-placement-coordinator.tsx +1399 -256
  90. package/src/components/tools/registry/move-registry-node-tool.tsx +1064 -0
  91. package/src/components/tools/roof/roof-tool.tsx +350 -28
  92. package/src/components/tools/select/box-select-state.ts +88 -0
  93. package/src/components/tools/select/box-select-tool.tsx +442 -520
  94. package/src/components/tools/select/marquee-geometry.test.ts +161 -0
  95. package/src/components/tools/select/marquee-geometry.ts +155 -0
  96. package/src/components/tools/select/plane-box-select-tool.tsx +570 -0
  97. package/src/components/tools/select/screen-rectangle-selection.ts +84 -0
  98. package/src/components/tools/select/select-candidates.test.ts +109 -0
  99. package/src/components/tools/select/select-candidates.ts +85 -0
  100. package/src/components/tools/shared/affordance-dispatch.ts +30 -0
  101. package/src/components/tools/shared/cursor-sphere.tsx +62 -26
  102. package/src/components/tools/shared/drag-bounding-box.tsx +195 -0
  103. package/src/components/tools/shared/facing-indicator.tsx +87 -0
  104. package/src/components/tools/shared/facing-pose-indicator.tsx +54 -0
  105. package/src/components/tools/shared/floor-stack-preview.ts +25 -0
  106. package/src/components/tools/shared/fresh-placement-visibility.ts +61 -0
  107. package/src/components/tools/shared/placement-box-geometry.ts +123 -0
  108. package/src/components/tools/shared/placement-box.tsx +305 -0
  109. package/src/components/tools/shared/polygon-editor.tsx +866 -175
  110. package/src/components/tools/shared/segment-angle.ts +56 -0
  111. package/src/components/tools/site/site-boundary-editor.tsx +520 -16
  112. package/src/components/tools/site/site-flag-model.ts +18 -0
  113. package/src/components/tools/stair/stair-defaults.ts +2 -1
  114. package/src/components/tools/stair/stair-tool.tsx +342 -37
  115. package/src/components/tools/tool-manager.tsx +239 -62
  116. package/src/components/tools/wall/wall-drafting.test.ts +330 -0
  117. package/src/components/tools/wall/wall-drafting.ts +248 -171
  118. package/src/components/tools/wall/wall-snap-geometry.test.ts +123 -0
  119. package/src/components/tools/wall/wall-snap-geometry.ts +331 -0
  120. package/src/components/tools/zone/zone-boundary-editor.tsx +5 -1
  121. package/src/components/tools/zone/zone-tool.tsx +86 -82
  122. package/src/components/ui/action-menu/action-button.tsx +21 -1
  123. package/src/components/ui/action-menu/camera-actions.tsx +24 -17
  124. package/src/components/ui/action-menu/control-modes.tsx +40 -170
  125. package/src/components/ui/action-menu/furnish-tools.tsx +5 -5
  126. package/src/components/ui/action-menu/index.tsx +3 -117
  127. package/src/components/ui/action-menu/measurement-control.tsx +188 -0
  128. package/src/components/ui/action-menu/structure-tools.tsx +27 -93
  129. package/src/components/ui/action-menu/view-toggles.tsx +279 -90
  130. package/src/components/ui/command-palette/editor-commands.tsx +20 -15
  131. package/src/components/ui/command-palette/index.tsx +5 -3
  132. package/src/components/ui/controls/material-paint-panel.tsx +152 -0
  133. package/src/components/ui/controls/material-picker.tsx +87 -177
  134. package/src/components/ui/controls/material-properties-editor.tsx +108 -0
  135. package/src/components/ui/controls/metric-control.tsx +142 -46
  136. package/src/components/ui/controls/scene-material-list.tsx +247 -0
  137. package/src/components/ui/controls/slider-control.tsx +88 -38
  138. package/src/components/ui/floating-level-selector.tsx +47 -10
  139. package/src/components/ui/helpers/building-helper.tsx +10 -23
  140. package/src/components/ui/helpers/contextual-helper-panel.tsx +428 -0
  141. package/src/components/ui/helpers/helper-manager.tsx +235 -23
  142. package/src/components/ui/helpers/item-helper.tsx +28 -32
  143. package/src/components/ui/helpers/registered-tool-helper.tsx +59 -0
  144. package/src/components/ui/helpers/roof-helper.tsx +10 -12
  145. package/src/components/ui/icon-ref.tsx +47 -0
  146. package/src/components/ui/item-catalog/catalog-items.tsx +40 -1
  147. package/src/components/ui/item-catalog/item-catalog.tsx +16 -36
  148. package/src/components/ui/level-duplicate-dialog.tsx +2 -1
  149. package/src/components/ui/panels/node-display.ts +17 -16
  150. package/src/components/ui/panels/panel-manager.tsx +55 -58
  151. package/src/components/ui/panels/panel-wrapper.tsx +238 -12
  152. package/src/components/ui/panels/parametric-inspector.tsx +482 -0
  153. package/src/components/ui/panels/reference-panel.tsx +54 -19
  154. package/src/components/ui/primitives/dropdown-menu.tsx +12 -8
  155. package/src/components/ui/primitives/shortcut-token.tsx +39 -3
  156. package/src/components/ui/primitives/sidebar.tsx +1 -0
  157. package/src/components/ui/scene-loader.tsx +1 -3
  158. package/src/components/ui/sidebar/app-sidebar.tsx +5 -1
  159. package/src/components/ui/sidebar/icon-rail.tsx +50 -31
  160. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +263 -0
  161. package/src/components/ui/sidebar/panels/items-panel/index.tsx +82 -8
  162. package/src/components/ui/sidebar/panels/plugins-panel.tsx +218 -0
  163. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +122 -41
  164. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +66 -7
  165. package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +267 -0
  166. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -1
  167. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +9 -5
  168. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +86 -0
  169. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -1
  170. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +7 -2
  171. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +92 -0
  172. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +75 -0
  173. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +3 -3
  174. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +86 -0
  175. package/src/components/ui/sidebar/panels/site-panel/index.tsx +42 -21
  176. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +31 -17
  177. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +2 -1
  178. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +140 -0
  179. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +48 -8
  180. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +132 -0
  181. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +9 -5
  182. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +86 -0
  183. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +7 -1
  184. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +2 -2
  185. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +112 -39
  186. package/src/components/ui/sidebar/panels/site-panel/tree-structure.ts +36 -0
  187. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -1
  188. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +7 -2
  189. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +3 -3
  190. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +51 -2
  191. package/src/components/ui/sidebar/tab-bar.tsx +75 -1
  192. package/src/components/ui/sidebar/use-plugin-panels.tsx +132 -0
  193. package/src/components/ui/snap-target-badge.test.tsx +40 -0
  194. package/src/components/ui/snap-target-badge.tsx +88 -0
  195. package/src/components/viewer-overlay.tsx +253 -61
  196. package/src/components/viewer-zone-system.tsx +7 -2
  197. package/src/hooks/use-auto-save.test.ts +14 -0
  198. package/src/hooks/use-auto-save.ts +64 -10
  199. package/src/hooks/use-ceiling-events.ts +176 -0
  200. package/src/hooks/use-drag-action.ts +127 -0
  201. package/src/hooks/use-keyboard.ts +493 -95
  202. package/src/hooks/use-selection.ts +64 -0
  203. package/src/index.tsx +451 -6
  204. package/src/lib/active-placement-surface.ts +35 -0
  205. package/src/lib/ceiling-plan-snap.ts +24 -0
  206. package/src/lib/constants.ts +6 -2
  207. package/src/lib/contextual-help.test.ts +112 -0
  208. package/src/lib/contextual-help.ts +144 -0
  209. package/src/lib/continuation.ts +64 -0
  210. package/src/lib/direct-manipulation.test.ts +192 -0
  211. package/src/lib/direct-manipulation.ts +109 -0
  212. package/src/lib/editor-api.ts +50 -0
  213. package/src/lib/elevator-support.ts +96 -0
  214. package/src/lib/floorplan/apply-alignment.test.ts +25 -0
  215. package/src/lib/floorplan/apply-alignment.ts +117 -0
  216. package/src/lib/floorplan/floorplan-export.tsx +364 -0
  217. package/src/lib/floorplan/geometry.ts +53 -0
  218. package/src/lib/floorplan/index.ts +10 -0
  219. package/src/lib/floorplan/items.ts +5 -2
  220. package/src/lib/floorplan/plan-coords.ts +21 -0
  221. package/src/lib/floorplan/selection-tool.ts +40 -0
  222. package/src/lib/floorplan/stairs.ts +12 -1
  223. package/src/lib/fresh-planar-placement.test.ts +339 -0
  224. package/src/lib/fresh-planar-placement.ts +130 -0
  225. package/src/lib/glb-export.test.ts +441 -0
  226. package/src/lib/glb-export.ts +874 -0
  227. package/src/lib/history.ts +11 -1
  228. package/src/lib/interaction/hot-set.test.ts +133 -0
  229. package/src/lib/interaction/hot-set.ts +67 -0
  230. package/src/lib/interaction/overlay-policy.test.ts +51 -0
  231. package/src/lib/interaction/overlay-policy.ts +59 -0
  232. package/src/lib/interaction/scope.ts +211 -0
  233. package/src/lib/level-duplication.ts +54 -42
  234. package/src/lib/level-selection.ts +2 -2
  235. package/src/lib/material-paint.ts +227 -48
  236. package/src/lib/measurement-kind.test.ts +30 -0
  237. package/src/lib/measurement-kind.ts +19 -0
  238. package/src/lib/measurement-label.test.ts +47 -0
  239. package/src/lib/measurement-label.ts +68 -0
  240. package/src/lib/measurement-parser.ts +116 -0
  241. package/src/lib/measurements.test.ts +183 -0
  242. package/src/lib/measurements.ts +199 -0
  243. package/src/lib/paint-scope.test.ts +454 -0
  244. package/src/lib/paint-scope.ts +461 -0
  245. package/src/lib/placement-drag-release.ts +23 -0
  246. package/src/lib/placement-metadata.ts +29 -0
  247. package/src/lib/planar-cursor-placement.test.ts +100 -0
  248. package/src/lib/planar-cursor-placement.ts +42 -0
  249. package/src/lib/plugin-panels.test.ts +19 -0
  250. package/src/lib/plugin-panels.ts +91 -0
  251. package/src/lib/quick-measurement.test.ts +77 -0
  252. package/src/lib/quick-measurement.ts +109 -0
  253. package/src/lib/roof-duplication.ts +7 -7
  254. package/src/lib/roof-hover-outline-proxy.ts +22 -0
  255. package/src/lib/roof-wall-hit.ts +164 -0
  256. package/src/lib/scene-clipboard.test.ts +196 -0
  257. package/src/lib/scene-clipboard.ts +332 -0
  258. package/src/lib/scene.ts +40 -8
  259. package/src/lib/selection-routing.test.ts +298 -0
  260. package/src/lib/selection-routing.ts +175 -0
  261. package/src/lib/sfx/index.ts +1 -0
  262. package/src/lib/sfx/movement-tick.test.ts +65 -0
  263. package/src/lib/sfx/movement-tick.ts +18 -0
  264. package/src/lib/sfx-bus.ts +69 -10
  265. package/src/lib/sfx-player.test.ts +124 -0
  266. package/src/lib/sfx-player.ts +148 -55
  267. package/src/lib/site-boundary.ts +1 -0
  268. package/src/lib/slab-plan-snap.test.ts +93 -0
  269. package/src/lib/slab-plan-snap.ts +108 -0
  270. package/src/lib/snapping-mode.test.ts +138 -0
  271. package/src/lib/snapping-mode.ts +179 -0
  272. package/src/lib/stair-duplication.ts +4 -4
  273. package/src/lib/stair-levels.test.ts +146 -0
  274. package/src/lib/stair-levels.ts +177 -0
  275. package/src/lib/surface-plan-snap.test.ts +71 -0
  276. package/src/lib/surface-plan-snap.ts +256 -0
  277. package/src/lib/use-linear-display.ts +40 -0
  278. package/src/lib/world-grid-snap.ts +231 -0
  279. package/src/lib/zone-content.ts +130 -0
  280. package/src/store/use-alignment-guides.ts +21 -0
  281. package/src/store/use-direct-manipulation-feedback.ts +20 -0
  282. package/src/store/use-editor.tsx +767 -114
  283. package/src/store/use-facing-pose.ts +44 -0
  284. package/src/store/use-fence-curve-draft.ts +21 -0
  285. package/src/store/use-floorplan-draft-preview.ts +101 -0
  286. package/src/store/use-floorplan-marquee.ts +50 -0
  287. package/src/store/use-interaction-scope.test.ts +186 -0
  288. package/src/store/use-interaction-scope.ts +132 -0
  289. package/src/store/use-measurement-draft.test.ts +530 -0
  290. package/src/store/use-measurement-draft.ts +543 -0
  291. package/src/store/use-opening-guides.ts +41 -0
  292. package/src/store/use-placement-preview.ts +39 -0
  293. package/src/store/use-quick-measurement-hud.test.ts +53 -0
  294. package/src/store/use-quick-measurement-hud.ts +77 -0
  295. package/src/store/use-segment-draft-chain.ts +28 -0
  296. package/src/store/use-stair-build-preview.ts +43 -0
  297. package/src/store/use-wall-move-ghosts.ts +36 -0
  298. package/src/store/use-wall-snap-indicator.ts +34 -0
  299. package/src/components/editor/first-person/bvh-ecctrl.tsx +0 -860
  300. package/src/components/editor/preset-thumbnail-generator.tsx +0 -125
  301. package/src/components/editor-2d/renderers/floorplan-roof-layer.tsx +0 -113
  302. package/src/components/tools/building/move-building-tool.tsx +0 -157
  303. package/src/components/tools/ceiling/ceiling-boundary-editor.tsx +0 -43
  304. package/src/components/tools/ceiling/ceiling-hole-editor.tsx +0 -49
  305. package/src/components/tools/ceiling/ceiling-tool.tsx +0 -465
  306. package/src/components/tools/ceiling/move-ceiling-tool.tsx +0 -264
  307. package/src/components/tools/column/column-tool.tsx +0 -97
  308. package/src/components/tools/column/move-column-tool.tsx +0 -105
  309. package/src/components/tools/door/door-math.ts +0 -110
  310. package/src/components/tools/door/door-tool.tsx +0 -324
  311. package/src/components/tools/door/move-door-tool.tsx +0 -412
  312. package/src/components/tools/fence/curve-fence-tool.tsx +0 -178
  313. package/src/components/tools/fence/fence-tool.tsx +0 -346
  314. package/src/components/tools/fence/move-fence-endpoint-tool.tsx +0 -441
  315. package/src/components/tools/fence/move-fence-tool.tsx +0 -302
  316. package/src/components/tools/item/item-tool.tsx +0 -26
  317. package/src/components/tools/roof/move-roof-tool.tsx +0 -364
  318. package/src/components/tools/slab/move-slab-tool.tsx +0 -182
  319. package/src/components/tools/slab/slab-boundary-editor.tsx +0 -43
  320. package/src/components/tools/slab/slab-hole-editor.tsx +0 -49
  321. package/src/components/tools/slab/slab-tool.tsx +0 -322
  322. package/src/components/tools/spawn/move-spawn-tool.tsx +0 -101
  323. package/src/components/tools/spawn/spawn-tool.tsx +0 -130
  324. package/src/components/tools/wall/curve-wall-tool.tsx +0 -178
  325. package/src/components/tools/wall/move-wall-endpoint-tool.tsx +0 -426
  326. package/src/components/tools/wall/move-wall-tool.tsx +0 -358
  327. package/src/components/tools/wall/wall-tool.tsx +0 -332
  328. package/src/components/tools/window/move-window-tool.tsx +0 -447
  329. package/src/components/tools/window/window-math.ts +0 -117
  330. package/src/components/tools/window/window-tool.tsx +0 -332
  331. package/src/components/ui/helpers/ceiling-helper.tsx +0 -20
  332. package/src/components/ui/helpers/slab-helper.tsx +0 -20
  333. package/src/components/ui/helpers/wall-helper.tsx +0 -20
  334. package/src/components/ui/panels/ceiling-panel.tsx +0 -249
  335. package/src/components/ui/panels/column-panel.tsx +0 -759
  336. package/src/components/ui/panels/door-panel.tsx +0 -1299
  337. package/src/components/ui/panels/fence-panel.tsx +0 -222
  338. package/src/components/ui/panels/item-panel.tsx +0 -306
  339. package/src/components/ui/panels/paint-panel.tsx +0 -163
  340. package/src/components/ui/panels/presets/presets-popover.tsx +0 -511
  341. package/src/components/ui/panels/roof-panel.tsx +0 -280
  342. package/src/components/ui/panels/roof-segment-panel.tsx +0 -311
  343. package/src/components/ui/panels/slab-panel.tsx +0 -250
  344. package/src/components/ui/panels/spawn-panel.tsx +0 -161
  345. package/src/components/ui/panels/stair-panel.tsx +0 -577
  346. package/src/components/ui/panels/stair-segment-panel.tsx +0 -325
  347. package/src/components/ui/panels/wall-panel.tsx +0 -273
  348. package/src/components/ui/panels/window-panel.tsx +0 -968
  349. package/src/contexts/presets-context.tsx +0 -121
  350. package/src/hooks/use-contextual-tools.ts +0 -61
@@ -0,0 +1,176 @@
1
+ import {
2
+ type AnyNodeId,
3
+ type CeilingEvent,
4
+ type CeilingNode,
5
+ emitter,
6
+ resolveLevelId,
7
+ sceneRegistry,
8
+ useScene,
9
+ } from '@pascal-app/core'
10
+ import { useViewer } from '@pascal-app/viewer'
11
+ import { useThree } from '@react-three/fiber'
12
+ import { useEffect, useRef } from 'react'
13
+ import { type Object3D, Plane, Raycaster, Vector2, Vector3 } from 'three'
14
+ import useEditor from '../store/use-editor'
15
+ import { getMovingNode } from '../store/use-interaction-scope'
16
+
17
+ const UP = new Vector3(0, 1, 0)
18
+
19
+ /** Ray-casting point-in-polygon on ceiling-local [x, z] tuples. */
20
+ function pointInPolygon(x: number, z: number, polygon: Array<[number, number]>): boolean {
21
+ let inside = false
22
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
23
+ const a = polygon[i]!
24
+ const b = polygon[j]!
25
+ const intersects =
26
+ a[1] > z !== b[1] > z && x < ((b[0] - a[0]) * (z - a[1])) / (b[1] - a[1]) + a[0]
27
+ if (intersects) inside = !inside
28
+ }
29
+ return inside
30
+ }
31
+
32
+ /**
33
+ * Reliable pointer events for placing ceiling-attached items.
34
+ *
35
+ * Mirrors {@link useGridEvents} (the floor path): rather than relying on the
36
+ * thin, single-sided `ceiling-grid` overlay mesh to be hit by R3F's raycaster —
37
+ * which misses from the "wrong" camera side, near polygon edges/holes, or while
38
+ * the overlay is mid-reveal, dropping the commit click even though the green box
39
+ * still shows — it intersects a math plane at each ceiling's height (double-sided,
40
+ * so it hits from above or below) and point-in-polygon tests the hit. Emits
41
+ * `ceiling:enter/move/leave/click` so both the placement coordinator and the 2D
42
+ * floor-plan item preview keep working.
43
+ *
44
+ * Active only while a ceiling-attached item is being placed or moved. The
45
+ * `ceiling-grid` mesh no longer emits these events (see `CeilingRenderer`), so
46
+ * this is the single, reliable source.
47
+ */
48
+ export function useCeilingEvents() {
49
+ const { camera, gl } = useThree()
50
+ const raycaster = useRef(new Raycaster())
51
+ const pointer = useRef(new Vector2())
52
+ const plane = useRef(new Plane(UP.clone(), 0))
53
+ const worldHit = useRef(new Vector3())
54
+ const meshWorld = useRef(new Vector3())
55
+ const hoveredRef = useRef<string | null>(null)
56
+
57
+ useEffect(() => {
58
+ const canvas = gl.domElement
59
+
60
+ const isActive = (): boolean => {
61
+ const ed = useEditor.getState()
62
+ if (ed.selectedItem?.attachTo === 'ceiling') return true
63
+ const moving = getMovingNode()
64
+ return moving?.type === 'item' && moving.asset?.attachTo === 'ceiling'
65
+ }
66
+
67
+ type Hit = { node: CeilingNode; mesh: Object3D; world: Vector3; local: Vector3 }
68
+
69
+ // The ceiling on the active level whose plane the cursor ray crosses inside
70
+ // its polygon, nearest the camera.
71
+ const pick = (nativeEvent: PointerEvent | MouseEvent): Hit | null => {
72
+ const activeLevelId = useViewer.getState().selection.levelId
73
+ if (!activeLevelId) return null
74
+
75
+ const rect = canvas.getBoundingClientRect()
76
+ pointer.current.x = ((nativeEvent.clientX - rect.left) / rect.width) * 2 - 1
77
+ pointer.current.y = -((nativeEvent.clientY - rect.top) / rect.height) * 2 + 1
78
+ raycaster.current.setFromCamera(pointer.current, camera)
79
+
80
+ const nodes = useScene.getState().nodes
81
+ const ceilingIds = sceneRegistry.byType.ceiling
82
+ if (!ceilingIds) return null
83
+
84
+ let best: Hit | null = null
85
+ let bestDist = Number.POSITIVE_INFINITY
86
+
87
+ for (const id of ceilingIds) {
88
+ const node = nodes[id as AnyNodeId] as CeilingNode | undefined
89
+ if (node?.type !== 'ceiling' || node.polygon.length < 3) continue
90
+ if (resolveLevelId(node, nodes) !== activeLevelId) continue
91
+ const mesh = sceneRegistry.nodes.get(id)
92
+ if (!mesh) continue
93
+
94
+ mesh.getWorldPosition(meshWorld.current)
95
+ plane.current.set(UP, -meshWorld.current.y)
96
+ if (!raycaster.current.ray.intersectPlane(plane.current, worldHit.current)) continue
97
+
98
+ const local = mesh.worldToLocal(worldHit.current.clone())
99
+ if (!pointInPolygon(local.x, local.z, node.polygon)) continue
100
+
101
+ const dist = raycaster.current.ray.origin.distanceToSquared(worldHit.current)
102
+ if (dist < bestDist) {
103
+ bestDist = dist
104
+ best = { node, mesh, world: worldHit.current.clone(), local }
105
+ }
106
+ }
107
+ return best
108
+ }
109
+
110
+ const buildEvent = (hit: Hit, nativeEvent: PointerEvent | MouseEvent): CeilingEvent => ({
111
+ node: hit.node,
112
+ position: [hit.world.x, hit.world.y, hit.world.z],
113
+ localPosition: [hit.local.x, hit.local.y, hit.local.z],
114
+ normal: [0, 1, 0],
115
+ object: hit.mesh,
116
+ stopPropagation: () => {},
117
+ nativeEvent: nativeEvent as never,
118
+ })
119
+
120
+ const emitLeave = (nativeEvent: PointerEvent | MouseEvent) => {
121
+ const id = hoveredRef.current
122
+ if (!id) return
123
+ hoveredRef.current = null
124
+ const node = useScene.getState().nodes[id as AnyNodeId] as CeilingNode | undefined
125
+ const mesh = sceneRegistry.nodes.get(id)
126
+ if (!node || !mesh) return
127
+ emitter.emit(
128
+ 'ceiling:leave',
129
+ buildEvent(
130
+ { node, mesh, world: meshWorld.current.clone(), local: new Vector3() },
131
+ nativeEvent,
132
+ ),
133
+ )
134
+ }
135
+
136
+ const onMove = (e: PointerEvent) => {
137
+ if (!isActive()) {
138
+ emitLeave(e)
139
+ return
140
+ }
141
+ const hit = pick(e)
142
+ if (!hit) {
143
+ emitLeave(e)
144
+ return
145
+ }
146
+ const ev = buildEvent(hit, e)
147
+ if (hoveredRef.current !== hit.node.id) {
148
+ if (hoveredRef.current) emitLeave(e)
149
+ hoveredRef.current = hit.node.id
150
+ emitter.emit('ceiling:enter', ev)
151
+ }
152
+ emitter.emit('ceiling:move', ev)
153
+ }
154
+
155
+ const onClick = (e: MouseEvent) => {
156
+ if (useViewer.getState().cameraDragging) return
157
+ if (e.button !== 0) return
158
+ if (!isActive()) return
159
+ const hit = pick(e)
160
+ if (!hit) return
161
+ emitter.emit('ceiling:click', buildEvent(hit, e))
162
+ }
163
+
164
+ const onPointerLeave = (e: PointerEvent) => emitLeave(e)
165
+
166
+ canvas.addEventListener('pointermove', onMove)
167
+ canvas.addEventListener('click', onClick)
168
+ canvas.addEventListener('pointerleave', onPointerLeave)
169
+
170
+ return () => {
171
+ canvas.removeEventListener('pointermove', onMove)
172
+ canvas.removeEventListener('click', onClick)
173
+ canvas.removeEventListener('pointerleave', onPointerLeave)
174
+ }
175
+ }, [camera, gl])
176
+ }
@@ -0,0 +1,127 @@
1
+ 'use client'
2
+
3
+ import {
4
+ type AnyNode,
5
+ type AnyNodeId,
6
+ type ChildQuery,
7
+ createDragSession,
8
+ createSceneApi,
9
+ type DragAction,
10
+ type DragSessionInput,
11
+ emitter,
12
+ type GridEvent,
13
+ type Modifiers,
14
+ type SpatialQuery,
15
+ useScene,
16
+ } from '@pascal-app/core'
17
+ import { useEffect, useRef } from 'react'
18
+
19
+ const sceneApi = createSceneApi(useScene)
20
+
21
+ function modifiersFromGridEvent(event: GridEvent): Modifiers {
22
+ // Both grid-event emit paths (use-grid-events.ts and the floorplan panel)
23
+ // store the raw DOM event directly at `.nativeEvent` — there is no second
24
+ // `.nativeEvent` hop.
25
+ const ne = event.nativeEvent as Partial<MouseEvent> | undefined
26
+ return {
27
+ shift: ne?.shiftKey ?? false,
28
+ alt: ne?.altKey ?? false,
29
+ ctrl: ne?.ctrlKey ?? false,
30
+ meta: ne?.metaKey ?? false,
31
+ }
32
+ }
33
+
34
+ export type UseDragActionArgs<Ctx, Draft> = {
35
+ /** When true the session is live: subscribes to grid events + Esc.
36
+ * Flipping to false (or unmount) cancels and cleans up. */
37
+ active: boolean
38
+ action: DragAction<Ctx, Draft>
39
+ /** Captured once at the moment `active` flips to true. */
40
+ initial: DragSessionInput
41
+ /** Relations cascade plumbing. */
42
+ spatialQuery?: SpatialQuery
43
+ childQuery?: ChildQuery
44
+ /** Fires once after `action.commit` returns true. */
45
+ onCommit?: () => void
46
+ /** Fires once after `action.cancel` (Esc, unmount, or commit-returns-false). */
47
+ onCancel?: () => void
48
+ /**
49
+ * Milliseconds after activation during which `grid:click` is swallowed.
50
+ * Stops the very click that mounted this tool (a DOM button or 3D
51
+ * handle elsewhere) from cascading into the grid and immediately
52
+ * committing the drag. Defaults to 150ms — matches the legacy guard
53
+ * used by every kind-owned tool entered via a click.
54
+ */
55
+ activationGraceMs?: number
56
+ }
57
+
58
+ /**
59
+ * React hook wrapping the pure `createDragSession` orchestrator with the
60
+ * editor's grid event emitter and an Esc-to-cancel keyboard binding.
61
+ *
62
+ * - Pauses scene history when active → resumes on commit/cancel/unmount
63
+ * - Per `grid:move` runs preview + snap + apply and cascades dirty marks
64
+ * - `grid:click` triggers commit; Escape triggers cancel
65
+ *
66
+ * For tests of the underlying behavior, drive `createDragSession` directly
67
+ * (no React needed). This hook is the thin glue.
68
+ */
69
+ export function useDragAction<Ctx, Draft>(args: UseDragActionArgs<Ctx, Draft>) {
70
+ // Stable refs so handlers don't re-bind when callbacks change.
71
+ const argsRef = useRef(args)
72
+ argsRef.current = args
73
+
74
+ useEffect(() => {
75
+ if (!args.active) return
76
+
77
+ const session = createDragSession<Ctx, Draft>(argsRef.current.action, sceneApi, {
78
+ spatialQuery: argsRef.current.spatialQuery,
79
+ childQuery: argsRef.current.childQuery,
80
+ onCommit: () => argsRef.current.onCommit?.(),
81
+ onCancel: () => argsRef.current.onCancel?.(),
82
+ })
83
+
84
+ session.start(argsRef.current.initial)
85
+
86
+ const activatedAt = Date.now()
87
+ const graceMs = argsRef.current.activationGraceMs ?? 150
88
+
89
+ const onMove = (event: GridEvent) => {
90
+ const point: readonly [number, number] = [event.localPosition[0], event.localPosition[2]]
91
+ session.move(point, modifiersFromGridEvent(event))
92
+ }
93
+
94
+ const onClick = (event: GridEvent) => {
95
+ // Swallow the click that mounted this tool — otherwise the very
96
+ // first grid:click cascades into commit() before any move().
97
+ if (Date.now() - activatedAt < graceMs) {
98
+ event.nativeEvent?.stopPropagation?.()
99
+ return
100
+ }
101
+ session.commit()
102
+ }
103
+
104
+ const onKeyDown = (e: KeyboardEvent) => {
105
+ if (e.key === 'Escape') session.cancel()
106
+ }
107
+
108
+ emitter.on('grid:move', onMove)
109
+ emitter.on('grid:click', onClick)
110
+ if (typeof window !== 'undefined') {
111
+ window.addEventListener('keydown', onKeyDown)
112
+ }
113
+
114
+ return () => {
115
+ emitter.off('grid:move', onMove)
116
+ emitter.off('grid:click', onClick)
117
+ if (typeof window !== 'undefined') {
118
+ window.removeEventListener('keydown', onKeyDown)
119
+ }
120
+ // If the parent flipped `active` to false (or unmounted) while we were
121
+ // still mid-drag, treat it as a cancel — no dangling history pause.
122
+ session.dispose()
123
+ }
124
+ }, [args.active])
125
+ }
126
+
127
+ export type { AnyNode, AnyNodeId, DragAction, Modifiers }