@pascal-app/editor 1.0.3 → 1.0.4
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.
- package/package.json +11 -9
- package/src/components/editor/action-menu-button.tsx +83 -0
- package/src/components/editor/bake-thumbnail.tsx +315 -4
- package/src/components/editor/capture-level-picker.tsx +72 -0
- package/src/components/editor/custom-camera-controls.tsx +202 -57
- package/src/components/editor/delete-confirmation-dialog.tsx +297 -7
- package/src/components/editor/duplicate-node.ts +244 -0
- package/src/components/editor/editor-layout-mobile.tsx +36 -25
- package/src/components/editor/editor-layout-v2.tsx +131 -58
- package/src/components/editor/export-manager.tsx +34 -8
- package/src/components/editor/first-person/build-collider-world.test.ts +51 -0
- package/src/components/editor/first-person/build-collider-world.ts +6 -2
- package/src/components/editor/first-person/mechanism-targets.test.ts +75 -0
- package/src/components/editor/first-person/mechanism-targets.ts +36 -0
- package/src/components/editor/first-person-controls.tsx +205 -2
- package/src/components/editor/floating-action-menu.tsx +63 -207
- package/src/components/editor/floor-aware-camera-controls.test.ts +442 -0
- package/src/components/editor/floor-aware-camera-controls.ts +324 -0
- package/src/components/editor/floor-openings-overlay.tsx +243 -0
- package/src/components/editor/floor-region-controls.tsx +846 -0
- package/src/components/editor/floor-region-webgpu-materials.test.ts +12 -0
- package/src/components/editor/floor-surface.test.ts +165 -0
- package/src/components/editor/floor-surface.ts +182 -0
- package/src/components/editor/floorplan-background-selection.test.ts +11 -2
- package/src/components/editor/floorplan-background-selection.ts +1 -3
- package/src/components/editor/floorplan-panel.tsx +344 -342
- package/src/components/editor/footprint-height-handle.tsx +204 -0
- package/src/components/editor/group-actions.ts +54 -2
- package/src/components/editor/handles/handle-hit-priority.test.tsx +63 -0
- package/src/components/editor/handles/handle-hit-priority.tsx +37 -0
- package/src/components/editor/handles/swallow-next-click.test.ts +28 -0
- package/src/components/editor/handles/use-handle-drag.ts +269 -197
- package/src/components/editor/index.tsx +294 -169
- package/src/components/editor/join-walls-pill.tsx +44 -0
- package/src/components/editor/node-action-menu.tsx +68 -70
- package/src/components/editor/node-arrow-handles.tsx +25 -6
- package/src/components/editor/open-wall-ends-3d-layer.tsx +273 -0
- package/src/components/editor/open-wall-ends-hint.tsx +89 -0
- package/src/components/editor/quick-measurement-hud.tsx +3 -2
- package/src/components/editor/registry-action-contributions.test.tsx +63 -0
- package/src/components/editor/registry-action-contributions.tsx +80 -1
- package/src/components/editor/room-controls.tsx +847 -0
- package/src/components/editor/room-floor-highlight.tsx +128 -0
- package/src/components/editor/room-handles-2d.tsx +354 -0
- package/src/components/editor/room-handles.tsx +675 -0
- package/src/components/editor/room-highlight.tsx +225 -0
- package/src/components/editor/room-labels.test.ts +357 -0
- package/src/components/editor/room-labels.tsx +990 -0
- package/src/components/editor/room-transform-ghost.tsx +256 -0
- package/src/components/editor/room-webgpu-materials.test.ts +27 -0
- package/src/components/editor/selection-manager.tsx +451 -317
- package/src/components/editor/slab-hole-highlights.tsx +3 -0
- package/src/components/editor/snapshot-capture-overlay.tsx +4 -0
- package/src/components/editor/snapshot-capture.test.ts +52 -4
- package/src/components/editor/snapshot-capture.ts +30 -5
- package/src/components/editor/thumbnail-generator.test.ts +308 -0
- package/src/components/editor/thumbnail-generator.tsx +1035 -229
- package/src/components/editor/use-floorplan-background-placement.ts +31 -11
- package/src/components/editor/vector-edge-extractor.tsx +121 -0
- package/src/components/editor/views/host-view.tsx +61 -0
- package/src/components/editor/views/plugins-view.tsx +670 -0
- package/src/components/editor/views/scene-region.tsx +59 -0
- package/src/components/editor/views/use-editor-views.ts +57 -0
- package/src/components/editor/views/view-bar.tsx +220 -0
- package/src/components/editor/wall-justification.test.ts +140 -0
- package/src/components/editor/wall-move-side-handles.tsx +43 -142
- package/src/components/editor/wall-push-arrow.tsx +92 -0
- package/src/components/editor/wall-region-handles.tsx +509 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +3 -0
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +8 -4
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.test.tsx +86 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +290 -0
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +11 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +113 -102
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.test.ts +156 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +278 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +77 -0
- package/src/components/editor-2d/renderers/{floorplan-draft-wall-measurement.tsx → floorplan-draft-measurement.tsx} +8 -8
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +4 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +38 -8
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +291 -227
- package/src/components/editor-2d/svg-paths.ts +12 -15
- package/src/components/procedural-items/inspector.tsx +40 -15
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.test.ts +97 -14
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +18 -18
- package/src/components/systems/zone/zone-system.test.ts +47 -0
- package/src/components/systems/zone/zone-system.tsx +29 -68
- package/src/components/tools/item/placement-history.test.tsx +474 -0
- package/src/components/tools/item/placement-strategies.ts +8 -4
- package/src/components/tools/item/use-draft-node.test.tsx +432 -1
- package/src/components/tools/item/use-draft-node.ts +166 -95
- package/src/components/tools/item/use-placement-coordinator.tsx +93 -46
- package/src/components/tools/paint-region/use-paint-tint.ts +37 -0
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +466 -0
- package/src/components/tools/registry/move-registry-node-tool.tsx +3 -1
- package/src/components/tools/select/box-select-tool.tsx +2 -12
- package/src/components/tools/select/plane-box-select-tool.test.tsx +79 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +35 -22
- package/src/components/tools/select/select-candidates.test.ts +37 -4
- package/src/components/tools/select/select-candidates.ts +15 -11
- package/src/components/tools/shared/cursor-sphere.tsx +36 -12
- package/src/components/tools/site/site-boundary-editor.tsx +1 -2
- package/src/components/tools/stair/stair-defaults.ts +0 -3
- package/src/components/tools/stair/stair-tool.tsx +90 -42
- package/src/components/tools/tool-manager.tsx +46 -20
- package/src/components/tools/wall/wall-drafting.test.ts +19 -4
- package/src/components/tools/zone/zone-tool.tsx +4 -12
- package/src/components/ui/action-menu/action-button.tsx +3 -0
- package/src/components/ui/action-menu/camera-actions.tsx +2 -1
- package/src/components/ui/action-menu/control-modes.tsx +2 -35
- package/src/components/ui/action-menu/measurement-control.tsx +3 -10
- package/src/components/ui/build-panel/build-panel.tsx +235 -0
- package/src/components/ui/command-palette/editor-commands.tsx +4 -30
- package/src/components/ui/command-palette/index.tsx +5 -24
- package/src/components/ui/controls/finish-swatch.tsx +110 -0
- package/src/components/ui/controls/material-paint-panel.tsx +97 -26
- package/src/components/ui/controls/material-picker.tsx +4 -1
- package/src/components/ui/controls/scene-material-list.tsx +4 -32
- package/src/components/ui/controls/select-control.tsx +65 -0
- package/src/components/ui/floating-level-selector.tsx +9 -14
- package/src/components/ui/helpers/building-helper.tsx +4 -1
- package/src/components/ui/helpers/contextual-helper-panel.tsx +154 -70
- package/src/components/ui/helpers/helper-manager.test.tsx +69 -0
- package/src/components/ui/helpers/helper-manager.tsx +325 -14
- package/src/components/ui/helpers/item-helper.tsx +8 -0
- package/src/components/ui/helpers/registered-tool-helper.tsx +8 -1
- package/src/components/ui/icon-ref.tsx +45 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/node-icon-image.tsx +16 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +20 -14
- package/src/components/ui/panels/floor-foundation-panel.tsx +551 -0
- package/src/components/ui/panels/floor-opening-panel.tsx +143 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +2 -2
- package/src/components/ui/panels/mobile-selection-bar.tsx +2 -2
- package/src/components/ui/panels/multi-field-value.test.ts +26 -3
- package/src/components/ui/panels/multi-field-value.ts +6 -3
- package/src/components/ui/panels/multi-parametric-inspector.tsx +52 -2
- package/src/components/ui/panels/multi-selection-panel.tsx +43 -4
- package/src/components/ui/panels/node-display.ts +8 -3
- package/src/components/ui/panels/panel-manager.tsx +103 -68
- package/src/components/ui/panels/panel-wrapper.tsx +78 -36
- package/src/components/ui/panels/parametric-field-control.tsx +1 -1
- package/src/components/ui/panels/parametric-inspector.tsx +4 -4
- package/src/components/ui/panels/reference-panel.tsx +2 -3
- package/src/components/ui/panels/room-construction-rows.tsx +774 -0
- package/src/components/ui/panels/room-name-options.test.ts +55 -0
- package/src/components/ui/panels/room-name-options.ts +47 -0
- package/src/components/ui/panels/room-openings-field.tsx +110 -0
- package/src/components/ui/panels/room-panel.tsx +725 -0
- package/src/components/ui/panels/shape-choice.tsx +58 -0
- package/src/components/ui/panels/wall-region-list.tsx +109 -0
- package/src/components/ui/primitives/color-dot.tsx +36 -24
- package/src/components/ui/primitives/sidebar.tsx +2 -0
- package/src/components/ui/right-stack.test.ts +29 -0
- package/src/components/ui/right-stack.tsx +145 -0
- package/src/components/ui/sidebar/icon-rail.tsx +5 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +31 -4
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +5 -5
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -4
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +197 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +24 -11
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +176 -211
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +30 -8
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +4 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +1 -4
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +21 -13
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +0 -27
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -3
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +9 -4
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +0 -2
- package/src/components/ui/sidebar/tab-bar.tsx +10 -0
- package/src/components/ui/sidebar/use-plugin-panels.tsx +15 -5
- package/src/components/viewer/floorplan-compass-button.tsx +9 -1
- package/src/components/viewer/floorplan-preview.tsx +5 -6
- package/src/components/viewer/viewer-hover-label.tsx +34 -0
- package/src/components/viewer/viewer-rooms.tsx +175 -0
- package/src/components/viewer/viewer-scene-header.tsx +181 -145
- package/src/components/viewer/viewer-selection-manager.tsx +124 -0
- package/src/components/viewer/viewer-stage.tsx +2 -2
- package/src/components/viewer-zone-system.tsx +3 -8
- package/src/hooks/use-auto-save.integration.test.tsx +123 -9
- package/src/hooks/use-auto-save.ts +34 -8
- package/src/hooks/use-keyboard.test.ts +178 -3
- package/src/hooks/use-keyboard.ts +89 -71
- package/src/hooks/use-open-wall-ends.test.ts +99 -0
- package/src/hooks/use-open-wall-ends.ts +238 -0
- package/src/hooks/use-placement-notice.test.ts +48 -0
- package/src/hooks/use-placement-notice.ts +42 -0
- package/src/hooks/use-selected-room.ts +143 -0
- package/src/index.tsx +246 -39
- package/src/lib/ceiling-edit-session.test.ts +321 -0
- package/src/lib/ceiling-edit-session.ts +206 -0
- package/src/lib/ceiling-region-session.test.ts +179 -0
- package/src/lib/continuation.test.ts +19 -1
- package/src/lib/continuation.ts +25 -4
- package/src/lib/door-interaction.ts +14 -0
- package/src/lib/editor-level-display.test.ts +96 -0
- package/src/lib/editor-level-display.ts +48 -0
- package/src/lib/editor-views.ts +144 -0
- package/src/lib/export-geometry-wait.test.ts +90 -0
- package/src/lib/floor-edit-session.ts +153 -0
- package/src/lib/floor-footprints.test.ts +563 -0
- package/src/lib/floor-footprints.ts +395 -0
- package/src/lib/floor-foundation-support.test.ts +283 -0
- package/src/lib/floor-opening-draft.ts +218 -0
- package/src/lib/floor-openings.test.ts +216 -0
- package/src/lib/floor-region-geometry.ts +191 -0
- package/src/lib/floor-region-session.test.ts +485 -0
- package/src/lib/floor-region-session.ts +589 -0
- package/src/lib/floor-region-snap.ts +101 -0
- package/src/lib/floor-step-hover.test.ts +32 -0
- package/src/lib/floorplan/annotation-visibility.ts +17 -0
- package/src/lib/floorplan/dimension-drive.test.ts +360 -0
- package/src/lib/floorplan/dimension-drive.ts +479 -0
- package/src/lib/floorplan/floorplan-export.test.ts +12 -8
- package/src/lib/floorplan/floorplan-export.tsx +32 -8
- package/src/lib/floorplan/floorplan-extension.ts +32 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +4 -0
- package/src/lib/floorplan/floorplan-mode.ts +2 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +339 -18
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +138 -8
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +56 -25
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +138 -0
- package/src/lib/floorplan/floorplan-readonly.ts +6 -0
- package/src/lib/floorplan/geometry.ts +13 -6
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/marks.test.ts +213 -0
- package/src/lib/floorplan/marks.ts +238 -0
- package/src/lib/floorplan/open-wall-ends.test.ts +268 -0
- package/src/lib/floorplan/open-wall-ends.ts +162 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Regular.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-GeistMono.txt +92 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-LiberationSans.txt +102 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Regular.ttf +0 -0
- package/src/lib/floorplan/schedules.test.ts +189 -0
- package/src/lib/floorplan/schedules.ts +339 -0
- package/src/lib/floorplan/sheet-export.test.ts +100 -0
- package/src/lib/floorplan/sheet-export.ts +318 -0
- package/src/lib/floorplan/site-plan/build-site-plan-drawing.ts +779 -0
- package/src/lib/floorplan/site-plan/contours.test.ts +43 -0
- package/src/lib/floorplan/site-plan/contributors.ts +97 -0
- package/src/lib/floorplan/site-plan/coverage.ts +232 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.test.ts +15 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.tsx +86 -0
- package/src/lib/floorplan/site-plan/front-edge.test.ts +103 -0
- package/src/lib/floorplan/site-plan/front-edge.ts +156 -0
- package/src/lib/floorplan/site-plan/geometry.test.ts +275 -0
- package/src/lib/floorplan/site-plan/geometry.ts +557 -0
- package/src/lib/floorplan/site-plan/index.ts +71 -0
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +366 -0
- package/src/lib/floorplan/site-plan/site-annotations.ts +1083 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +379 -0
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +138 -0
- package/src/lib/floorplan/site-plan/street-name.test.ts +69 -0
- package/src/lib/floorplan/site-plan/street-name.ts +302 -0
- package/src/lib/floorplan/site-plan/yards.test.ts +69 -0
- package/src/lib/floorplan/types.ts +1 -27
- package/src/lib/fresh-planar-placement.test.ts +36 -0
- package/src/lib/fresh-planar-placement.ts +59 -36
- package/src/lib/geometry-script/author.ts +152 -0
- package/src/lib/geometry-script/client.ts +152 -0
- package/src/lib/geometry-script/protocol.ts +12 -0
- package/src/lib/gesture-lifecycle.test.ts +595 -0
- package/src/lib/gesture-lifecycle.ts +290 -0
- package/src/lib/glb-export-zone-holes.test.ts +41 -0
- package/src/lib/glb-export.test.ts +485 -0
- package/src/lib/glb-export.ts +237 -119
- package/src/lib/history.test.ts +6 -0
- package/src/lib/history.ts +7 -0
- package/src/lib/hud-title.ts +109 -0
- package/src/lib/hydration-gated-storage.ts +49 -0
- package/src/lib/ifc-export.test.ts +174 -0
- package/src/lib/ifc-export.ts +201 -0
- package/src/lib/ifc-parts.ts +15 -0
- package/src/lib/inspector-expanded.test.ts +44 -0
- package/src/lib/inspector-expanded.ts +36 -0
- package/src/lib/interaction/scope.ts +18 -0
- package/src/lib/keyboard-pan.test.ts +129 -7
- package/src/lib/keyboard-pan.ts +161 -12
- package/src/lib/live-gesture-round-trip.test.ts +360 -0
- package/src/lib/lot/__fixtures__/map-dossier-miami-shores.json +1 -0
- package/src/lib/lot/__fixtures__/map-dossier-stpete.json +1 -0
- package/src/lib/lot/clean-ring.test.ts +186 -0
- package/src/lib/lot/clean-ring.ts +217 -0
- package/src/lib/lot/dossier.test.ts +202 -0
- package/src/lib/lot/dossier.ts +498 -0
- package/src/lib/lot/drop-in.test.ts +326 -0
- package/src/lib/lot/drop-in.ts +407 -0
- package/src/lib/lot/index.ts +43 -0
- package/src/lib/lot/lot-patch.test.ts +340 -0
- package/src/lib/lot/lot-patch.ts +394 -0
- package/src/lib/lot/parcel-provider.ts +43 -0
- package/src/lib/lot/terrain.test.ts +161 -0
- package/src/lib/lot/terrain.ts +266 -0
- package/src/lib/material-catalog-model.ts +3 -1
- package/src/lib/material-paint-panel-model.ts +9 -5
- package/src/lib/material-paint.ts +4 -0
- package/src/lib/mezzanine-actions.test.ts +342 -0
- package/src/lib/mezzanine-draft.test.ts +501 -0
- package/src/lib/mezzanine-draft.ts +278 -0
- package/src/lib/mezzanine-messages.ts +26 -0
- package/src/lib/mezzanine-selection.test.ts +207 -0
- package/src/lib/mezzanine-stairs.ts +46 -0
- package/src/lib/model-export.ts +3 -1
- package/src/lib/node-action-movement.ts +17 -6
- package/src/lib/node-display-label.ts +37 -0
- package/src/lib/orbit-floor-clearance.test.ts +165 -0
- package/src/lib/orbit-floor-clearance.ts +106 -0
- package/src/lib/paint-commit-route.test.ts +37 -0
- package/src/lib/paint-commit-route.ts +17 -0
- package/src/lib/paint-eyedropper.test.tsx +165 -0
- package/src/lib/paint-eyedropper.ts +99 -0
- package/src/lib/paint-pass-through.test.ts +111 -0
- package/src/lib/paint-pass-through.ts +76 -0
- package/src/lib/paint-region-hover.ts +25 -0
- package/src/lib/paint-region-mode.ts +154 -0
- package/src/lib/paint-regions.test.ts +166 -0
- package/src/lib/paint-regions.ts +192 -0
- package/src/lib/paint-scope.test.ts +317 -35
- package/src/lib/paint-scope.ts +266 -25
- package/src/lib/panel-rows.ts +21 -0
- package/src/lib/parametric-node-update.ts +1 -1
- package/src/lib/plate-paint-affected.test.ts +300 -0
- package/src/lib/plate-paint-affected.ts +177 -0
- package/src/lib/plugin-chat.ts +50 -0
- package/src/lib/plugin-panels.test.ts +25 -0
- package/src/lib/plugin-panels.ts +94 -0
- package/src/lib/print-shell-compiler.ts +1 -0
- package/src/lib/registered-draft-snap.ts +12 -0
- package/src/lib/roof-duplication.ts +10 -2
- package/src/lib/room-assembly-overlay.test.ts +275 -0
- package/src/lib/room-assembly-overlay.ts +266 -0
- package/src/lib/room-built-on.test.ts +379 -0
- package/src/lib/room-built-on.ts +138 -0
- package/src/lib/room-construction-commands.ts +712 -0
- package/src/lib/room-construction.test.ts +746 -0
- package/src/lib/room-construction.ts +385 -0
- package/src/lib/room-controls-phase6.test.ts +630 -0
- package/src/lib/room-divide-session.ts +523 -0
- package/src/lib/room-handle-drag.ts +1068 -0
- package/src/lib/room-name-catalog.test.ts +90 -0
- package/src/lib/room-name-catalog.ts +168 -0
- package/src/lib/room-push-dimensions.test.ts +311 -0
- package/src/lib/room-push-dimensions.ts +251 -0
- package/src/lib/room-selection-commands.ts +62 -0
- package/src/lib/room-selection.test.ts +973 -0
- package/src/lib/room-selection.ts +417 -0
- package/src/lib/room-structure-commands.ts +94 -0
- package/src/lib/room-structure.test.ts +921 -0
- package/src/lib/room-transform-session.ts +570 -0
- package/src/lib/room-zone-routing.test.ts +294 -0
- package/src/lib/room-zone-routing.ts +197 -0
- package/src/lib/scene-clipboard.test.ts +364 -0
- package/src/lib/scene-clipboard.ts +229 -48
- package/src/lib/scene-material-refs.test.ts +79 -0
- package/src/lib/scene-material-refs.ts +79 -0
- package/src/lib/scene.test.ts +24 -36
- package/src/lib/scene.ts +33 -57
- package/src/lib/selection-routing.test.ts +129 -45
- package/src/lib/selection-routing.ts +53 -74
- package/src/lib/session-writes.test.ts +120 -0
- package/src/lib/session-writes.ts +205 -0
- package/src/lib/sidebar-panel.ts +62 -0
- package/src/lib/site-boundary.test.ts +4 -6
- package/src/lib/site-boundary.ts +1 -1
- package/src/lib/snapping-mode.test.ts +4 -0
- package/src/lib/snapping-mode.ts +8 -1
- package/src/lib/terrace-draft.test.ts +145 -0
- package/src/lib/terrace-draft.ts +213 -0
- package/src/lib/tool-cursor-icon.test.ts +16 -0
- package/src/lib/tool-cursor-icon.ts +11 -0
- package/src/lib/typing-target.ts +9 -0
- package/src/lib/units.ts +77 -39
- package/src/lib/vector-edges.test.ts +58 -0
- package/src/lib/vector-edges.ts +400 -0
- package/src/lib/viewer-selection.test.ts +577 -0
- package/src/lib/viewer-selection.ts +569 -0
- package/src/lib/wall-draw-variant.test.ts +71 -0
- package/src/lib/wall-draw-variant.ts +91 -0
- package/src/lib/wall-paint-region-session.ts +246 -0
- package/src/lib/wall-paint-region.test.ts +373 -0
- package/src/lib/wall-polygon-draft.test.ts +262 -0
- package/src/lib/wall-polygon-draft.ts +286 -0
- package/src/lib/wall-push.test.ts +453 -0
- package/src/lib/wall-region-face.ts +352 -0
- package/src/lib/wall-region-handles.test.ts +304 -0
- package/src/lib/wall-region-handles.ts +368 -0
- package/src/lib/wall-region-list.test.ts +119 -0
- package/src/lib/wall-region-list.ts +136 -0
- package/src/lib/wall-region-snap.ts +110 -0
- package/src/lib/window-interaction.ts +14 -0
- package/src/lib/zone-content.ts +4 -1
- package/src/lib/zone-name.test.ts +17 -0
- package/src/lib/zone-name.ts +17 -0
- package/src/store/opens-in-select-mode.test.ts +223 -0
- package/src/store/paint-mode.test.ts +188 -0
- package/src/store/terrain-sculpt-mode.test.ts +19 -21
- package/src/store/tool-mode.test.ts +137 -6
- package/src/store/use-delete-confirmation.ts +28 -1
- package/src/store/use-drawing-view.test.ts +24 -3
- package/src/store/use-drawing-view.ts +29 -1
- package/src/store/use-editor.tsx +432 -321
- package/src/store/use-floorplan-draft-preview.ts +13 -0
- package/src/store/use-floorplan-marquee.ts +12 -2
- package/src/store/use-quick-measurement-hud.ts +3 -3
- package/src/store/use-stair-build-preview.ts +13 -5
- package/src/store/use-wall-move-ghosts.ts +4 -2
- package/src/store/use-wall-region-handles-selection.test.ts +222 -0
- package/src/store/use-wall-region-handles-selection.ts +139 -0
- package/src/store/view-layout.test.ts +175 -0
- package/src/store/view-layout.ts +196 -0
- package/src/test-utils/immediate-animation-frames.ts +16 -0
- package/src/test-utils/live-gesture-round-trip.ts +224 -0
- package/src/test-utils/selection-harness.ts +82 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +0 -499
- package/src/components/systems/zone/zone-label-editor-system.tsx +0 -333
- package/src/components/tools/fence/fence-drafting.test.ts +0 -100
- package/src/components/tools/fence/fence-drafting.ts +0 -266
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +0 -218
- package/src/components/viewer/viewer-units-panel.tsx +0 -116
- package/src/lib/floorplan/stairs.ts +0 -489
- package/src/lib/level-duplication.test.ts +0 -144
- package/src/lib/level-duplication.ts +0 -195
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type AlignmentAnchor,
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
|
+
beginSceneHistoryPauseSession,
|
|
6
7
|
type CeilingEvent,
|
|
7
8
|
canHostSurfaceChild,
|
|
8
9
|
collectAlignmentAnchors,
|
|
@@ -10,6 +11,8 @@ import {
|
|
|
10
11
|
findLevelAncestorId,
|
|
11
12
|
type GridEvent,
|
|
12
13
|
getScaledDimensions,
|
|
14
|
+
getWallBodyCenterOffset,
|
|
15
|
+
getWallLocalFaceZ,
|
|
13
16
|
type ItemEvent,
|
|
14
17
|
movingFootprintAnchors,
|
|
15
18
|
type NodeEvent,
|
|
@@ -25,7 +28,6 @@ import {
|
|
|
25
28
|
useScene,
|
|
26
29
|
useSpatialQuery,
|
|
27
30
|
type WallEvent,
|
|
28
|
-
type WallNode,
|
|
29
31
|
} from '@pascal-app/core'
|
|
30
32
|
import { useViewer } from '@pascal-app/viewer'
|
|
31
33
|
import { Html } from '@react-three/drei'
|
|
@@ -55,7 +57,7 @@ import { sfxEmitter } from '../../../lib/sfx-bus'
|
|
|
55
57
|
import {
|
|
56
58
|
surfaceAttachmentId,
|
|
57
59
|
surfaceFramePose,
|
|
58
|
-
updateSurfaceNode,
|
|
60
|
+
updateSurfaceNode as writeSurfaceNode,
|
|
59
61
|
} from '../../../lib/surface-attachment'
|
|
60
62
|
import {
|
|
61
63
|
projectAlignmentGuidesWorldToActiveBuildingLocal,
|
|
@@ -68,6 +70,7 @@ import useEditor, {
|
|
|
68
70
|
isMagneticSnapActive,
|
|
69
71
|
} from '../../../store/use-editor'
|
|
70
72
|
import useFacingPose from '../../../store/use-facing-pose'
|
|
73
|
+
import { getMovingNode } from '../../../store/use-interaction-scope'
|
|
71
74
|
import usePlacementPreview from '../../../store/use-placement-preview'
|
|
72
75
|
import {
|
|
73
76
|
createItemSurfaceGridDispatch,
|
|
@@ -116,7 +119,7 @@ import {
|
|
|
116
119
|
} from './placement-strategies'
|
|
117
120
|
import { resolveItemPlacementSurfaceNormal } from './placement-surface'
|
|
118
121
|
import type { PlacementState, TransitionResult } from './placement-types'
|
|
119
|
-
import type
|
|
122
|
+
import { type DraftNodeHandle, type ItemCopy, pausedDraftWrite } from './use-draft-node'
|
|
120
123
|
|
|
121
124
|
const DEFAULT_DIMENSIONS: [number, number, number] = [1, 1, 1]
|
|
122
125
|
|
|
@@ -262,20 +265,20 @@ basePlaneMaterial.opacityNode = radialOpacity
|
|
|
262
265
|
|
|
263
266
|
export interface PlacementCoordinatorConfig {
|
|
264
267
|
asset: AssetInput | null
|
|
268
|
+
/** Scale to use when lazily creating a draft (e.g. for wall/ceiling duplicates). Defaults to [1,1,1]. */
|
|
269
|
+
defaultScale?: [number, number, number]
|
|
265
270
|
draftNode: DraftNodeHandle
|
|
266
271
|
initDraft: (gridPosition: Vector3) => void
|
|
267
|
-
onCommitted: () => boolean
|
|
268
|
-
onCancel?: () => void
|
|
269
272
|
initialState?: PlacementState
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
/** Painted slot overrides to seed onto a lazily-created draft (wall/ceiling
|
|
273
|
-
* duplicates) so the duplicate keeps its materials. */
|
|
274
|
-
slots?: ItemNode['slots']
|
|
273
|
+
onCancel?: () => void
|
|
274
|
+
onCommitted: () => boolean
|
|
275
275
|
/** Move-mode sessions keep the grabbed item offset from the first surface hit
|
|
276
276
|
* (floor / wall / ceiling / item-surface / shelf) instead of snapping the
|
|
277
277
|
* item's origin under the cursor. */
|
|
278
278
|
preserveDragOffset?: boolean
|
|
279
|
+
/** The item a duplicate copies, for a lazily-created draft (wall/ceiling
|
|
280
|
+
* duplicates) to keep its materials and collections. */
|
|
281
|
+
copied?: ItemCopy
|
|
279
282
|
}
|
|
280
283
|
|
|
281
284
|
export function usePlacementCoordinator(config: PlacementCoordinatorConfig): React.ReactNode {
|
|
@@ -528,7 +531,14 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
528
531
|
|
|
529
532
|
useEffect(() => {
|
|
530
533
|
if (!asset) return
|
|
531
|
-
|
|
534
|
+
// History is paused only around the placement's own writes, never for the whole carry:
|
|
535
|
+
// the draft stays out of history snapshots (core's history-drafts), so writes others make
|
|
536
|
+
// mid-carry record as their own steps, with space detection. In split view the 2D move
|
|
537
|
+
// overlay co-owns the gesture (keyed by the moving node), and the drop's commitStep lifts
|
|
538
|
+
// its pause too.
|
|
539
|
+
const movingNodeId = getMovingNode()?.id
|
|
540
|
+
const updateSurfaceNode: typeof writeSurfaceNode = (...args) =>
|
|
541
|
+
pausedDraftWrite(() => writeSurfaceNode(...args))
|
|
532
542
|
|
|
533
543
|
const validators = { canPlaceOnFloor, canPlaceOnWall, canPlaceOnCeiling }
|
|
534
544
|
|
|
@@ -608,7 +618,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
608
618
|
}
|
|
609
619
|
|
|
610
620
|
useAlignmentGuides.getState().clear()
|
|
611
|
-
useScene.temporal.getState().resume()
|
|
612
621
|
if (committedId) {
|
|
613
622
|
useViewer.getState().setSelection({ selectedIds: [committedId as AnyNodeId] })
|
|
614
623
|
}
|
|
@@ -631,14 +640,22 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
631
640
|
) => {
|
|
632
641
|
const draftId = draftNode.current?.id ?? null
|
|
633
642
|
const wasAdopted = draftNode.isAdopted
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
643
|
+
const drop = beginSceneHistoryPauseSession(useScene, { gesture: movingNodeId })
|
|
644
|
+
let finalId: string | null
|
|
645
|
+
try {
|
|
646
|
+
finalId = drop.commitStep(() =>
|
|
647
|
+
draftNode.commit(nodeUpdate, {
|
|
648
|
+
...options,
|
|
649
|
+
onReject: (reason) => {
|
|
650
|
+
feedback.reject(reason)
|
|
651
|
+
edgeMaterial.color.setHex(0xef_44_44)
|
|
652
|
+
basePlaneMaterial.color.setHex(0xef_44_44)
|
|
653
|
+
},
|
|
654
|
+
}),
|
|
655
|
+
)
|
|
656
|
+
} finally {
|
|
657
|
+
drop.end()
|
|
658
|
+
}
|
|
642
659
|
if (finalId && draftId) {
|
|
643
660
|
useLiveTransforms.getState().clear(draftId)
|
|
644
661
|
useLiveNodeOverrides.getState().clearFields(draftId, faceHostClearFields(draftNode.current))
|
|
@@ -832,16 +849,15 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
832
849
|
asset,
|
|
833
850
|
initRotation,
|
|
834
851
|
configRef.current.defaultScale,
|
|
835
|
-
configRef.current.
|
|
852
|
+
configRef.current.copied,
|
|
836
853
|
)
|
|
837
854
|
|
|
838
855
|
const draft = draftNode.current
|
|
839
856
|
if (draft) {
|
|
840
857
|
Object.assign(draft, result.nodeUpdate)
|
|
841
858
|
// One-time setup: put node in the right parent so it renders correctly
|
|
842
|
-
if (result.surfaceId
|
|
843
|
-
|
|
844
|
-
else updateSurfaceNode(draft.id, result.nodeUpdate)
|
|
859
|
+
if (result.surfaceId === undefined) updateSurfaceNode(draft.id, result.nodeUpdate)
|
|
860
|
+
else draftNode.updateSurface(result.nodeUpdate, result.surfaceId)
|
|
845
861
|
disableDraftRaycastNow()
|
|
846
862
|
}
|
|
847
863
|
|
|
@@ -1276,7 +1292,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1276
1292
|
asset,
|
|
1277
1293
|
currentRotation,
|
|
1278
1294
|
configRef.current.defaultScale,
|
|
1279
|
-
configRef.current.
|
|
1295
|
+
configRef.current.copied,
|
|
1280
1296
|
)
|
|
1281
1297
|
const previewBounds = expandBoundsToGrid(
|
|
1282
1298
|
getFallbackPreviewBounds(draftNode.current, asset, asset.attachTo),
|
|
@@ -1427,12 +1443,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1427
1443
|
const rot = result.nodeUpdate?.rotation
|
|
1428
1444
|
if (rot) mesh.rotation.y = rot[1]
|
|
1429
1445
|
|
|
1430
|
-
|
|
1431
|
-
if (asset.attachTo === 'wall-side' && placementState.current.wallId) {
|
|
1446
|
+
if (placementState.current.wallId) {
|
|
1432
1447
|
const parentWall = useScene.getState().nodes[placementState.current.wallId as AnyNodeId]
|
|
1433
1448
|
if (parentWall?.type === 'wall') {
|
|
1434
|
-
|
|
1435
|
-
|
|
1449
|
+
mesh.position.z =
|
|
1450
|
+
asset.attachTo === 'wall-side'
|
|
1451
|
+
? getWallLocalFaceZ(parentWall, draft.side === 'front' ? 'a' : 'b')
|
|
1452
|
+
: draft.position[2] + getWallBodyCenterOffset(parentWall)
|
|
1436
1453
|
}
|
|
1437
1454
|
}
|
|
1438
1455
|
}
|
|
@@ -1600,7 +1617,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1600
1617
|
const segment =
|
|
1601
1618
|
useScene.getState().nodes[placementState.current.roofSegmentId as AnyNodeId]
|
|
1602
1619
|
if (segment?.type === 'roof-segment') {
|
|
1603
|
-
mesh.position.z = (segment.wallThickness ?? 0.1
|
|
1620
|
+
mesh.position.z = getWallLocalFaceZ({ thickness: segment.wallThickness ?? 0.1 }, 'a')
|
|
1604
1621
|
}
|
|
1605
1622
|
}
|
|
1606
1623
|
const rot = result.nodeUpdate?.rotation
|
|
@@ -1640,10 +1657,12 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1640
1657
|
applyTransition(result)
|
|
1641
1658
|
const draft = draftNode.current
|
|
1642
1659
|
if (draft) {
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1660
|
+
pausedDraftWrite(() =>
|
|
1661
|
+
useScene.getState().updateNode(draft.id, {
|
|
1662
|
+
parentId: result.nodeUpdate.parentId as string,
|
|
1663
|
+
roofSegmentId: undefined,
|
|
1664
|
+
}),
|
|
1665
|
+
)
|
|
1647
1666
|
}
|
|
1648
1667
|
} else {
|
|
1649
1668
|
// Create mode: destroy transient and reset state
|
|
@@ -1758,7 +1777,8 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1758
1777
|
}
|
|
1759
1778
|
if (draftNode.isAdopted) {
|
|
1760
1779
|
applyTransition(result)
|
|
1761
|
-
if (draft)
|
|
1780
|
+
if (draft)
|
|
1781
|
+
pausedDraftWrite(() => useScene.getState().updateNode(draft.id, result.nodeUpdate))
|
|
1762
1782
|
} else {
|
|
1763
1783
|
draftNode.destroy()
|
|
1764
1784
|
gridPosition.current.set(...result.gridPosition)
|
|
@@ -1863,6 +1883,8 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1863
1883
|
}
|
|
1864
1884
|
if (event.node.id === draftNode.current?.id) return
|
|
1865
1885
|
has3DPointerDrivenMoveRef.current = true
|
|
1886
|
+
// An authored object's underside takes ceiling items (a pendant under a vault).
|
|
1887
|
+
if (enterFaceHost(event)) return
|
|
1866
1888
|
const result = itemSurfaceStrategy.enter(surfaceContext(event, generic), event)
|
|
1867
1889
|
if (!result) return
|
|
1868
1890
|
feedback.clear()
|
|
@@ -1880,6 +1902,17 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1880
1902
|
|
|
1881
1903
|
const onItemMove = (event: NodeEvent<AnyNode>, generic = false) => {
|
|
1882
1904
|
if (event.node.id === draftNode.current?.id) return
|
|
1905
|
+
if (
|
|
1906
|
+
placementState.current.surface === 'block-face' &&
|
|
1907
|
+
placementState.current.blockId === event.node.id
|
|
1908
|
+
) {
|
|
1909
|
+
onFaceHostMove(event)
|
|
1910
|
+
return
|
|
1911
|
+
}
|
|
1912
|
+
if (placementState.current.surface !== 'block-face' && enterFaceHost(event)) {
|
|
1913
|
+
releaseCommit = () => onFaceHostClick(event)
|
|
1914
|
+
return
|
|
1915
|
+
}
|
|
1883
1916
|
releaseCommit = () => onItemClick(event)
|
|
1884
1917
|
has3DPointerDrivenMoveRef.current = true
|
|
1885
1918
|
if (!cursorGroupRef.current) return
|
|
@@ -1931,9 +1964,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1931
1964
|
}
|
|
1932
1965
|
|
|
1933
1966
|
const surfaceWorld =
|
|
1934
|
-
ctx.state.surfaceItemId
|
|
1935
|
-
?
|
|
1936
|
-
:
|
|
1967
|
+
ctx.state.surfaceItemId === null
|
|
1968
|
+
? null
|
|
1969
|
+
: resolveHostSurfaceWorld(ctx.state.surfaceItemId, event.position)
|
|
1937
1970
|
const itemMoveEvent = surfaceWorld ? { ...event, position: surfaceWorld } : event
|
|
1938
1971
|
lastRawPos.current.set(
|
|
1939
1972
|
itemMoveEvent.position[0],
|
|
@@ -1980,6 +2013,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1980
2013
|
const onItemLeave = (event: NodeEvent<AnyNode>) => {
|
|
1981
2014
|
if (event.node.type === 'cabinet') return
|
|
1982
2015
|
if (event.node.id === draftNode.current?.id) return
|
|
2016
|
+
if (
|
|
2017
|
+
placementState.current.surface === 'block-face' &&
|
|
2018
|
+
placementState.current.blockId === event.node.id
|
|
2019
|
+
) {
|
|
2020
|
+
onFaceHostLeave(event)
|
|
2021
|
+
return
|
|
2022
|
+
}
|
|
1983
2023
|
if (placementState.current.surface !== 'item-surface') return
|
|
1984
2024
|
|
|
1985
2025
|
event.stopPropagation()
|
|
@@ -1995,6 +2035,13 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
1995
2035
|
const onItemClick = (event: NodeEvent<AnyNode>) => {
|
|
1996
2036
|
gridDispatch.flush()
|
|
1997
2037
|
if (feedback.reason) return
|
|
2038
|
+
if (
|
|
2039
|
+
placementState.current.surface === 'block-face' &&
|
|
2040
|
+
placementState.current.blockId === event.node.id
|
|
2041
|
+
) {
|
|
2042
|
+
onFaceHostClick(event)
|
|
2043
|
+
return
|
|
2044
|
+
}
|
|
1998
2045
|
// Click on the draft item itself. R3F dispatches click events to
|
|
1999
2046
|
// the closest intersected mesh only — when the draft is hovering
|
|
2000
2047
|
// on a host (shelf / table / etc.) the draft's mesh is *above*
|
|
@@ -2309,9 +2356,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2309
2356
|
return
|
|
2310
2357
|
}
|
|
2311
2358
|
const shelfWorld =
|
|
2312
|
-
ctx.state.shelfId
|
|
2313
|
-
?
|
|
2314
|
-
:
|
|
2359
|
+
ctx.state.shelfId === null
|
|
2360
|
+
? null
|
|
2361
|
+
: resolveHostSurfaceWorld(ctx.state.shelfId, event.position)
|
|
2315
2362
|
const shelfMoveEvent = shelfWorld ? { ...event, position: shelfWorld } : event
|
|
2316
2363
|
const result = shelfSurfaceStrategy.move(ctx, shelfMoveEvent)
|
|
2317
2364
|
if (!result) return
|
|
@@ -2613,7 +2660,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2613
2660
|
if (event.button !== 2) return
|
|
2614
2661
|
const down = rightDown
|
|
2615
2662
|
rightDown = null
|
|
2616
|
-
if (!down
|
|
2663
|
+
if (!(down && configRef.current.onCancel)) return
|
|
2617
2664
|
const movedSq = (event.clientX - down.x) ** 2 + (event.clientY - down.y) ** 2
|
|
2618
2665
|
const elapsed = performance.now() - down.t
|
|
2619
2666
|
if (movedSq <= RIGHT_CLICK_CANCEL_MAX_MOVE_PX ** 2 && elapsed <= RIGHT_CLICK_CANCEL_MAX_MS) {
|
|
@@ -2662,8 +2709,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2662
2709
|
const draft = draftNode.current
|
|
2663
2710
|
if (draft === null) return
|
|
2664
2711
|
if (draft.id in useScene.getState().nodes) return
|
|
2665
|
-
|
|
2666
|
-
useScene.getState().createNode(draft, draft.parentId as AnyNodeId)
|
|
2712
|
+
pausedDraftWrite(() => useScene.getState().createNode(draft, draft.parentId as AnyNodeId))
|
|
2667
2713
|
})
|
|
2668
2714
|
})
|
|
2669
2715
|
|
|
@@ -2765,7 +2811,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2765
2811
|
useLiveNodeOverrides.getState().clearFields(draftNode.current.id, ['rotation'])
|
|
2766
2812
|
}
|
|
2767
2813
|
draftNode.destroy()
|
|
2768
|
-
useScene.temporal.getState().resume()
|
|
2769
2814
|
gridDispatch.cancel()
|
|
2770
2815
|
emitter.off('grid:move', gridDispatch.schedule)
|
|
2771
2816
|
emitter.off('grid:click', onGridClick)
|
|
@@ -2862,7 +2907,9 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|
|
2862
2907
|
)
|
|
2863
2908
|
return
|
|
2864
2909
|
draft.parentId = viewerLevelId
|
|
2865
|
-
|
|
2910
|
+
pausedDraftWrite(() =>
|
|
2911
|
+
useScene.getState().updateNode(draft.id as AnyNodeId, { parentId: viewerLevelId }),
|
|
2912
|
+
)
|
|
2866
2913
|
}, [viewerLevelId, draftNode, asset])
|
|
2867
2914
|
|
|
2868
2915
|
// Restore the draft mesh's raycast when the coordinator unmounts (tool change).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCatalogMaterialById,
|
|
3
|
+
parseMaterialRef,
|
|
4
|
+
type SceneMaterialId,
|
|
5
|
+
useScene,
|
|
6
|
+
} from '@pascal-app/core'
|
|
7
|
+
import { useMemo } from 'react'
|
|
8
|
+
import { usePaintRegionMode } from '../../../lib/paint-region-mode'
|
|
9
|
+
import useEditor from '../../../store/use-editor'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The paint material's colour for a region preview: a library preset's
|
|
13
|
+
* preview colour, a scene material's colour, or a plain material colour;
|
|
14
|
+
* `fallback` for the eraser or a material with no cheap colour.
|
|
15
|
+
*/
|
|
16
|
+
export function usePaintTint(fallback: string): string {
|
|
17
|
+
const active = useEditor((state) => state.activePaintMaterial)
|
|
18
|
+
const eraser = usePaintRegionMode((state) => state.mode) === 'erase'
|
|
19
|
+
const materials = useScene((state) => state.materials)
|
|
20
|
+
return useMemo(() => {
|
|
21
|
+
if (eraser) return fallback
|
|
22
|
+
const parsed = parseMaterialRef(active?.materialPreset)
|
|
23
|
+
if (parsed?.kind === 'library') {
|
|
24
|
+
const color = getCatalogMaterialById(parsed.id)?.previewColor
|
|
25
|
+
if (color) return color
|
|
26
|
+
}
|
|
27
|
+
if (parsed?.kind === 'scene') {
|
|
28
|
+
const color = materials[parsed.id as SceneMaterialId]?.material.properties?.color
|
|
29
|
+
if (color) return color
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
active?.material?.properties?.color ??
|
|
33
|
+
getCatalogMaterialById(active?.material?.id)?.previewColor ??
|
|
34
|
+
fallback
|
|
35
|
+
)
|
|
36
|
+
}, [active, eraser, materials, fallback])
|
|
37
|
+
}
|