@pascal-app/editor 1.0.7 → 1.1.1
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 +9 -15
- package/src/components/editor/action-menu-button.tsx +1 -1
- package/src/components/editor/alignment-3d-guide-layer.tsx +1 -1
- package/src/components/editor/custom-camera-controls.tsx +101 -45
- package/src/components/editor/duplicate-node.ts +2 -1
- package/src/components/editor/editor-layout-v2.tsx +1 -1
- package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
- package/src/components/editor/first-person-controls.tsx +20 -1983
- package/src/components/editor/fit-scene-framing.test.ts +318 -0
- package/src/components/editor/fit-scene-framing.ts +142 -0
- package/src/components/editor/floating-action-menu.tsx +5 -3
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floor-openings-overlay.tsx +1 -1
- package/src/components/editor/floor-region-controls.tsx +8 -4
- package/src/components/editor/floorplan-navigation-presentation.test.ts +0 -40
- package/src/components/editor/floorplan-navigation-presentation.ts +0 -66
- package/src/components/editor/floorplan-panel.tsx +199 -30
- package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
- package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
- package/src/components/editor/follow-pascal.test.tsx +1 -2
- package/src/components/editor/follow-pascal.tsx +1 -1
- package/src/components/editor/footprint-height-handle.tsx +2 -2
- package/src/components/editor/group-actions.ts +1 -2
- package/src/components/editor/group-floating-action-menu.tsx +1 -1
- package/src/components/editor/group-move-3d.ts +1 -2
- package/src/components/editor/group-rotate-handle.tsx +1 -2
- package/src/components/editor/group-transform-shared.ts +3 -1
- package/src/components/editor/handles/use-handle-drag.ts +1 -2
- package/src/components/editor/index.tsx +43 -13
- package/src/components/editor/inspector-extension-actions.tsx +1 -1
- package/src/components/editor/measurement-pill.tsx +1 -1
- package/src/components/editor/node-arrow-handles.tsx +2 -2
- package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
- package/src/components/editor/open-wall-ends-hint.tsx +1 -1
- package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
- package/src/components/editor/quick-measurement-card.tsx +1 -1
- package/src/components/editor/room-controls.tsx +10 -6
- package/src/components/editor/room-handles-2d.tsx +3 -3
- package/src/components/editor/room-handles.tsx +4 -5
- package/src/components/editor/room-highlight.tsx +6 -105
- package/src/components/editor/room-labels.test.ts +8 -822
- package/src/components/editor/room-labels.tsx +41 -1670
- package/src/components/editor/room-webgpu-materials.test.ts +1 -1
- package/src/components/editor/selection-manager.tsx +5 -3
- package/src/components/editor/site-edge-labels.tsx +7 -3
- package/src/components/editor/snapshot-capture-overlay.tsx +2 -5
- package/src/components/editor/use-floorplan-background-placement.ts +2 -1
- package/src/components/editor/views/plugins-view.tsx +1 -1
- package/src/components/editor/views/view-bar.tsx +9 -9
- package/src/components/editor/wall-measurement-label.tsx +31 -15
- package/src/components/editor/wall-move-side-handles.tsx +11 -7
- package/src/components/editor/wall-pull-grip.tsx +2 -2
- package/src/components/editor/wall-region-handles.tsx +2 -2
- package/src/components/editor/wall-snap-beacon-layer.tsx +53 -32
- package/src/components/editor-2d/floorplan-group-move.tsx +3 -4
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +13 -13
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +2 -3
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +23 -6
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +0 -37
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +0 -30
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +13 -3
- package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +14 -3
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +30 -10
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +39 -35
- package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
- package/src/components/systems/roof/roof-edit-system.tsx +33 -21
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
- package/src/components/tools/distribution/distribution-run-tool.tsx +151 -33
- package/src/components/tools/item/move-tool.tsx +1 -6
- package/src/components/tools/item/placement-history.test.tsx +1 -1
- package/src/components/tools/item/use-placement-coordinator.tsx +3 -4
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +7 -3
- package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +39 -16
- package/src/components/tools/shared/cursor-sphere.tsx +1 -1
- package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
- package/src/components/tools/shared/placement-box.tsx +2 -6
- package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
- package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
- package/src/components/tools/shared/segment-angle.ts +0 -4
- package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
- package/src/components/tools/tool-manager.tsx +1 -24
- package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
- package/src/components/tools/wall/wall-typed-entry.ts +70 -0
- package/src/components/ui/action-menu/camera-actions.tsx +2 -2
- package/src/components/ui/action-menu/control-modes.tsx +1 -1
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +1 -1
- package/src/components/ui/action-menu/index.tsx +3 -3
- package/src/components/ui/action-menu/measurement-control.tsx +3 -3
- package/src/components/ui/action-menu/placement.ts +0 -18
- package/src/components/ui/action-menu/point-ask-button.tsx +1 -1
- package/src/components/ui/action-menu/view-toggles.tsx +5 -5
- package/src/components/ui/controls/finish-swatch.tsx +1 -1
- package/src/components/ui/controls/material-paint-panel.tsx +2 -2
- package/src/components/ui/controls/scene-material-list.tsx +2 -2
- package/src/components/ui/controls/select-control.tsx +1 -1
- package/src/components/ui/controls/slider-control.tsx +18 -6
- package/src/components/ui/controls/terrain-sculpt-panel.tsx +1 -1
- package/src/components/ui/controls/tool-options-panel.tsx +74 -44
- package/src/components/ui/floating-level-selector.tsx +3 -3
- package/src/components/ui/helpers/contextual-helper-panel.tsx +1 -1
- package/src/components/ui/helpers/helper-manager.test.tsx +54 -1
- package/src/components/ui/helpers/helper-manager.tsx +55 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/panels/collections/collections-popover.tsx +2 -2
- package/src/components/ui/panels/floor-foundation-panel.tsx +3 -3
- package/src/components/ui/panels/floor-opening-panel.tsx +5 -5
- package/src/components/ui/panels/mobile-selection-bar.tsx +28 -24
- package/src/components/ui/panels/multi-height-mode.tsx +3 -3
- package/src/components/ui/panels/multi-selection-panel.tsx +1 -1
- package/src/components/ui/panels/node-display.ts +1 -1
- package/src/components/ui/panels/panel-manager.tsx +5 -3
- package/src/components/ui/panels/panel-wrapper.tsx +42 -19
- package/src/components/ui/panels/parametric-inspector.tsx +1 -1
- package/src/components/ui/panels/room-construction-rows.tsx +7 -7
- package/src/components/ui/panels/room-name-options.ts +1 -5
- package/src/components/ui/panels/room-openings-field.tsx +1 -1
- package/src/components/ui/panels/room-panel.tsx +7 -9
- package/src/components/ui/primitives/color-dot.tsx +2 -2
- package/src/components/ui/primitives/opacity-control.tsx +2 -2
- package/src/components/ui/primitives/sidebar.tsx +3 -3
- package/src/components/ui/right-stack.test.ts +13 -6
- package/src/components/ui/right-stack.tsx +22 -11
- package/src/components/ui/sidebar/icon-rail.tsx +1 -1
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +2 -2
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +2 -2
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +2 -6
- package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +3 -10
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +46 -7
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx +14 -5
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +3 -3
- package/src/components/ui/sidebar/tab-bar.tsx +1 -1
- package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +2 -2
- package/src/components/ui/wall-type/wall-type-menu.tsx +1 -1
- package/src/components/viewer-overlay.tsx +1 -2
- package/src/hooks/use-auto-frame.ts +1 -2
- package/src/hooks/use-keyboard.ts +1 -2
- package/src/hooks/use-selected-room.ts +5 -7
- package/src/i18n/floor-footprint-name.ts +1 -1
- package/src/i18n/locales/en/messages.po +1036 -306
- package/src/i18n/locales/en/messages.ts +1 -1
- package/src/i18n/locales/en-XA/messages.ts +1 -1
- package/src/i18n/locales/es/messages.po +2267 -439
- package/src/i18n/locales/fr/messages.po +2267 -439
- package/src/i18n/locales/ja/messages.po +2267 -439
- package/src/i18n/locales/zh-CN/messages.po +2267 -439
- package/src/i18n/locales.test.ts +1 -1
- package/src/index.tsx +183 -178
- package/src/lib/below-grade.test.tsx +4 -4
- package/src/lib/camera-facing.test.ts +1 -1
- package/src/lib/camera-facing.ts +2 -3
- package/src/lib/contextual-help.ts +6 -0
- package/src/lib/editor-level-display.ts +1 -1
- package/src/lib/elevation-guides.ts +21 -6
- package/src/lib/elevator-support.ts +1 -72
- package/src/lib/floor-footprints.test.ts +3 -3
- package/src/lib/floor-footprints.ts +1 -9
- package/src/lib/floor-foundation-support.test.ts +8 -3
- package/src/lib/floor-opening-draft.ts +2 -2
- package/src/lib/floor-region-session.ts +1 -1
- package/src/lib/floorplan/annotation-visibility.test.ts +1 -1
- package/src/lib/floorplan/annotation-visibility.ts +1 -1
- package/src/lib/floorplan/floorplan-export.test.ts +1 -1
- package/src/lib/floorplan/floorplan-export.tsx +8 -11
- package/src/lib/floorplan/floorplan-extension.ts +4 -157
- package/src/lib/floorplan/floorplan-mode.ts +2 -1
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +1 -1
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +8 -6
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +3 -4
- package/src/lib/floorplan/geometry.ts +2 -112
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +2 -1
- package/src/lib/floorplan/open-wall-ends.ts +2 -1
- package/src/lib/floorplan/schedules.ts +6 -3
- package/src/lib/floorplan/sheet-export.ts +7 -3
- package/src/lib/floorplan/site-plan/site-parts.ts +7 -1
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +1 -1
- package/src/lib/follow-pascal-presentation.ts +1 -1
- package/src/lib/gesture-lifecycle.ts +3 -1
- package/src/lib/glb-export.ts +1 -1
- package/src/lib/interaction/scope.ts +1 -0
- package/src/lib/layer-thickness.ts +1 -1
- package/src/lib/level-selection.test.ts +18 -2
- package/src/lib/level-selection.ts +31 -8
- package/src/lib/linear-display.ts +1 -1
- package/src/lib/live-gesture-round-trip.test.ts +1 -1
- package/src/lib/material-paint.ts +1 -1
- package/src/lib/measurement-label.test.ts +1 -1
- package/src/lib/measurements.test.ts +7 -5
- package/src/lib/mezzanine-selection.test.ts +1 -1
- package/src/lib/node-action-movement.test.tsx +115 -0
- package/src/lib/node-action-movement.ts +2 -0
- package/src/lib/paint-region-mode.ts +1 -1
- package/src/lib/placement-metadata.ts +4 -0
- package/src/lib/point-ask/describe-target.ts +6 -8
- package/src/lib/point-ask/region.ts +1 -1
- package/src/lib/point-ask/session.ts +1 -2
- package/src/lib/print-shell-compiler.ts +12 -1
- package/src/lib/print-wall-solids.test.ts +11 -0
- package/src/lib/print-wall-solids.ts +9 -0
- package/src/lib/roof-duplication.test.ts +100 -0
- package/src/lib/roof-duplication.ts +30 -5
- package/src/lib/room-built-on.test.ts +2 -5
- package/src/lib/room-built-on.ts +1 -15
- package/src/lib/room-construction-commands.ts +3 -2
- package/src/lib/room-controls-phase6.test.ts +1 -1
- package/src/lib/room-handle-drag.ts +8 -37
- package/src/lib/room-name-catalog.test.ts +2 -1
- package/src/lib/room-name-messages.test.ts +2 -1
- package/src/lib/room-name-messages.ts +1 -118
- package/src/lib/room-name-storage.test.ts +2 -1
- package/src/lib/room-push-dimensions.test.ts +1 -1
- package/src/lib/room-selection-commands.ts +2 -2
- package/src/lib/room-selection.test.ts +6 -6
- package/src/lib/room-transform-session.ts +1 -2
- package/src/lib/room-zone-routing.ts +2 -2
- package/src/lib/scene-clipboard.ts +2 -1
- package/src/lib/selection-routing.test.ts +0 -28
- package/src/lib/selection-routing.ts +1 -40
- package/src/lib/sfx-bus.ts +8 -32
- package/src/lib/sfx-player.test.ts +72 -1
- package/src/lib/sfx-player.ts +49 -337
- package/src/lib/snapping-mode.test.ts +23 -1
- package/src/lib/viewer-selection.test.ts +38 -10
- package/src/lib/wall-pull.test.ts +1 -1
- package/src/lib/wall-pull.ts +1 -27
- package/src/lib/wall-region-list.ts +3 -1
- package/src/lib/window-interaction.test.ts +4 -2
- package/src/store/use-editor.tsx +22 -26
- package/src/store/use-floorplan-annotation-visibility.ts +5 -5
- package/src/store/use-placement-typing.test.ts +165 -0
- package/src/store/use-placement-typing.ts +186 -0
- package/src/store/use-wall-region-handles-selection.ts +1 -2
- package/src/components/editor/__bench__/room-label-placement.bench.ts +0 -108
- package/src/components/editor/first-person/build-collider-world.test.ts +0 -596
- package/src/components/editor/first-person/build-collider-world.ts +0 -549
- package/src/components/editor/first-person/ground-holes.test.ts +0 -128
- package/src/components/editor/first-person/ground-holes.ts +0 -130
- package/src/components/editor/first-person/mechanism-targets.test.ts +0 -162
- package/src/components/editor/first-person/mechanism-targets.ts +0 -88
- package/src/components/editor/first-person/terrain-collider.test.ts +0 -132
- package/src/components/editor/first-person/terrain-collider.ts +0 -212
- package/src/components/editor/floorplan-camera-sync.test.ts +0 -249
- package/src/components/editor/floorplan-camera-sync.ts +0 -213
- package/src/components/editor/localized-html.tsx +0 -22
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +0 -236
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +0 -708
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +0 -385
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +0 -670
- package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +0 -89
- package/src/components/editor-2d/renderers/floorplan-label-angle.ts +0 -106
- package/src/components/editor-2d/svg-paths.ts +0 -124
- package/src/components/tools/elevator/elevator-defaults.ts +0 -8
- package/src/components/tools/elevator/elevator-tool.tsx +0 -372
- package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
- package/src/components/ui/action-menu/action-button.tsx +0 -89
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +0 -42
- package/src/components/ui/primitives/button.tsx +0 -69
- package/src/components/ui/primitives/dropdown-menu.tsx +0 -232
- package/src/components/ui/primitives/popover.tsx +0 -42
- package/src/components/ui/primitives/switch.tsx +0 -29
- package/src/components/ui/primitives/tooltip.tsx +0 -57
- package/src/components/ui/scene-loader.tsx +0 -73
- package/src/components/viewer/floorplan-compass-button.tsx +0 -67
- package/src/components/viewer/floorplan-preview-geometry.test.ts +0 -107
- package/src/components/viewer/floorplan-preview-geometry.ts +0 -281
- package/src/components/viewer/floorplan-preview-navigation.test.ts +0 -43
- package/src/components/viewer/floorplan-preview-navigation.ts +0 -62
- package/src/components/viewer/floorplan-preview-visibility.test.ts +0 -35
- package/src/components/viewer/floorplan-preview-visibility.ts +0 -19
- package/src/components/viewer/floorplan-preview.tsx +0 -1065
- package/src/components/viewer/render-settings-menu.tsx +0 -294
- package/src/components/viewer/sky-control.tsx +0 -710
- package/src/components/viewer/use-viewer-camera-navigation-sync.ts +0 -140
- package/src/components/viewer/use-viewer-ui-sounds.test.ts +0 -15
- package/src/components/viewer/use-viewer-ui-sounds.ts +0 -46
- package/src/components/viewer/viewer-controls-bar.tsx +0 -496
- package/src/components/viewer/viewer-hover-label.tsx +0 -42
- package/src/components/viewer/viewer-rooms.tsx +0 -248
- package/src/components/viewer/viewer-scene-header.tsx +0 -286
- package/src/components/viewer/viewer-selection-manager.tsx +0 -124
- package/src/components/viewer/viewer-stage-modes.test.ts +0 -38
- package/src/components/viewer/viewer-stage-modes.ts +0 -49
- package/src/components/viewer/viewer-stage-switcher.tsx +0 -97
- package/src/components/viewer/viewer-stage.test.tsx +0 -47
- package/src/components/viewer/viewer-stage.tsx +0 -221
- package/src/components/walkthrough-hud.tsx +0 -193
- package/src/hooks/use-mobile.ts +0 -19
- package/src/i18n/level-name.ts +0 -39
- package/src/i18n/scene-theme-name.ts +0 -16
- package/src/lib/below-grade.ts +0 -133
- package/src/lib/camera-pose.test.ts +0 -237
- package/src/lib/camera-pose.ts +0 -172
- package/src/lib/door-interaction.ts +0 -102
- package/src/lib/floorplan/floorplan-extension.test.ts +0 -42
- package/src/lib/floorplan/floorplan-readonly.test.ts +0 -47
- package/src/lib/floorplan/floorplan-readonly.ts +0 -95
- package/src/lib/floorplan/marks.test.ts +0 -213
- package/src/lib/floorplan/marks.ts +0 -238
- package/src/lib/measurement-label.ts +0 -68
- package/src/lib/measurements.ts +0 -225
- package/src/lib/node-display-label.ts +0 -37
- package/src/lib/room-assembly-overlay.test.ts +0 -275
- package/src/lib/room-assembly-overlay.ts +0 -265
- package/src/lib/room-selection.ts +0 -417
- package/src/lib/scene-bounds.test.ts +0 -183
- package/src/lib/scene-bounds.ts +0 -169
- package/src/lib/typing-target.ts +0 -9
- package/src/lib/viewer-selection.ts +0 -595
- package/src/lib/window-interaction.ts +0 -142
- package/src/lib/zone-content.ts +0 -133
- package/src/store/camera-pose-store.test.ts +0 -29
- package/src/store/camera-pose-store.ts +0 -27
- package/src/store/navigation-sync-pose-store.test.ts +0 -34
- package/src/store/navigation-sync-pose-store.ts +0 -27
- package/src/store/use-audio.test.ts +0 -146
- package/src/store/use-audio.tsx +0 -169
- package/src/store/use-first-person-hud.ts +0 -40
- package/src/store/use-follow-pascal.test.ts +0 -62
- package/src/store/use-follow-pascal.ts +0 -53
|
@@ -5,15 +5,6 @@ export type FloorplanPresentationViewBox = {
|
|
|
5
5
|
height: number
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export function setFloorplanCompassRotation(
|
|
9
|
-
compass: { style: { transform: string } } | null,
|
|
10
|
-
rotationDeg: number,
|
|
11
|
-
): void {
|
|
12
|
-
if (compass) {
|
|
13
|
-
compass.style.transform = `rotate(${rotationDeg}deg)`
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
8
|
type FloorplanRotationPresentation = {
|
|
18
9
|
svg: {
|
|
19
10
|
style: {
|
|
@@ -78,63 +69,6 @@ export function canApplyFloorplanNavigationSync(interactionInProgress: boolean):
|
|
|
78
69
|
return !interactionInProgress
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
export type FloorplanNavigationSyncScheduler<Pose> = {
|
|
82
|
-
update: (pose: Pose) => void
|
|
83
|
-
flush: () => void
|
|
84
|
-
discard: () => void
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function createFloorplanNavigationSyncScheduler<Pose>({
|
|
88
|
-
applyPresentation,
|
|
89
|
-
commit,
|
|
90
|
-
settleMs = 120,
|
|
91
|
-
schedule = globalThis.setTimeout,
|
|
92
|
-
cancel = globalThis.clearTimeout,
|
|
93
|
-
}: {
|
|
94
|
-
applyPresentation: (pose: Pose) => void
|
|
95
|
-
commit: (pose: Pose) => void
|
|
96
|
-
settleMs?: number
|
|
97
|
-
schedule?: (callback: () => void, delay: number) => ReturnType<typeof globalThis.setTimeout>
|
|
98
|
-
cancel?: (timer: ReturnType<typeof globalThis.setTimeout>) => void
|
|
99
|
-
}): FloorplanNavigationSyncScheduler<Pose> {
|
|
100
|
-
let latestPose: Pose | null = null
|
|
101
|
-
let settleTimer: ReturnType<typeof globalThis.setTimeout> | null = null
|
|
102
|
-
|
|
103
|
-
const clearSettleTimer = () => {
|
|
104
|
-
if (settleTimer === null) return
|
|
105
|
-
cancel(settleTimer)
|
|
106
|
-
settleTimer = null
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const flush = () => {
|
|
110
|
-
clearSettleTimer()
|
|
111
|
-
if (latestPose === null) return
|
|
112
|
-
const pose = latestPose
|
|
113
|
-
latestPose = null
|
|
114
|
-
commit(pose)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const update = (pose: Pose) => {
|
|
118
|
-
latestPose = pose
|
|
119
|
-
applyPresentation(pose)
|
|
120
|
-
clearSettleTimer()
|
|
121
|
-
settleTimer = schedule(() => {
|
|
122
|
-
settleTimer = null
|
|
123
|
-
if (latestPose === null) return
|
|
124
|
-
const settledPose = latestPose
|
|
125
|
-
latestPose = null
|
|
126
|
-
commit(settledPose)
|
|
127
|
-
}, settleMs)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const discard = () => {
|
|
131
|
-
clearSettleTimer()
|
|
132
|
-
latestPose = null
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return { update, flush, discard }
|
|
136
|
-
}
|
|
137
|
-
|
|
138
72
|
export function finalizeFloorplanNavigation<RotationState>({
|
|
139
73
|
zoomPending,
|
|
140
74
|
panActive,
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
type AnyNode,
|
|
6
6
|
type AnyNodeId,
|
|
7
7
|
type BuildingNode,
|
|
8
|
+
buildFloorplanContext,
|
|
9
|
+
buildSvgPolylinePath,
|
|
8
10
|
type CameraControlFrameEvent,
|
|
9
11
|
type CeilingNode,
|
|
10
12
|
CeilingNode as CeilingNodeSchema,
|
|
@@ -18,8 +20,13 @@ import {
|
|
|
18
20
|
type ElevatorNode,
|
|
19
21
|
emitter,
|
|
20
22
|
type FenceNode,
|
|
23
|
+
FLOORPLAN_VIEW_ROTATION_DEG,
|
|
21
24
|
type FloorplanGeometry,
|
|
25
|
+
floorplanLocalToWorldPoint,
|
|
26
|
+
formatAngleRadians,
|
|
27
|
+
formatLinearMeasurement,
|
|
22
28
|
formatNumber as formatLocalizedNumber,
|
|
29
|
+
formatPolygonPath,
|
|
23
30
|
type GeometryContext,
|
|
24
31
|
type GuideNode,
|
|
25
32
|
getRenderableSlabPolygon,
|
|
@@ -29,6 +36,7 @@ import {
|
|
|
29
36
|
type ItemNode,
|
|
30
37
|
isCurvedWall,
|
|
31
38
|
type LevelNode,
|
|
39
|
+
linearUnitToMeters,
|
|
32
40
|
loadAssetUrl,
|
|
33
41
|
newZone,
|
|
34
42
|
nodeRegistry,
|
|
@@ -38,6 +46,7 @@ import {
|
|
|
38
46
|
type RoofSegmentNode,
|
|
39
47
|
resolveSlabPlacementElevation,
|
|
40
48
|
resolveTerrainWallConstructionOptions,
|
|
49
|
+
rotatePlanVector as rotateSharedPlanVector,
|
|
41
50
|
runAsSingleSceneHistoryStep,
|
|
42
51
|
type SeparatorNode,
|
|
43
52
|
type SiteNode,
|
|
@@ -61,9 +70,24 @@ import {
|
|
|
61
70
|
WindowNode as WindowNodeSchema,
|
|
62
71
|
wallClosesRoom,
|
|
63
72
|
wallRectangleCorners,
|
|
73
|
+
worldToFloorplanLocalPoint,
|
|
64
74
|
} from '@pascal-app/core'
|
|
65
75
|
import { useSegmentDraftChain, useWallSnapIndicator } from '@pascal-app/editor'
|
|
66
76
|
import { getSceneTheme, useViewer } from '@pascal-app/viewer'
|
|
77
|
+
import {
|
|
78
|
+
createFloorplanNavigationSyncScheduler,
|
|
79
|
+
FloorplanCompassButton,
|
|
80
|
+
FloorplanGeometryRenderer,
|
|
81
|
+
type FloorplanNavigationSyncScheduler,
|
|
82
|
+
framingAnimates,
|
|
83
|
+
type NavigationSyncPose,
|
|
84
|
+
navigationSyncPoseStore,
|
|
85
|
+
publishNavigationSyncPose,
|
|
86
|
+
setFloorplanCompassRotation,
|
|
87
|
+
subscribeFloorplanCameraNavigation,
|
|
88
|
+
subscribeNavigationSyncPose,
|
|
89
|
+
useFloorplanCameraSyncBridge,
|
|
90
|
+
} from '@pascal-app/viewer/ui'
|
|
67
91
|
import { Command, Ruler } from 'lucide-react'
|
|
68
92
|
import {
|
|
69
93
|
type ComponentProps,
|
|
@@ -92,14 +116,9 @@ import {
|
|
|
92
116
|
alignFloorplanDraftPoint,
|
|
93
117
|
buildFloorplanItemEntry,
|
|
94
118
|
collectLevelDescendants,
|
|
95
|
-
FLOORPLAN_VIEW_ROTATION_DEG,
|
|
96
|
-
floorplanLocalToWorldPoint,
|
|
97
119
|
getFloorplanWall as getSharedFloorplanWall,
|
|
98
|
-
rotatePlanVector as rotateSharedPlanVector,
|
|
99
120
|
type FloorplanNodeTransform as SharedFloorplanNodeTransform,
|
|
100
|
-
worldToFloorplanLocalPoint,
|
|
101
121
|
} from '../../lib/floorplan'
|
|
102
|
-
import { buildFloorplanContext } from '../../lib/floorplan/floorplan-readonly'
|
|
103
122
|
// Site-plan view. Owned under `lib/floorplan/site-plan/**`; this panel
|
|
104
123
|
// only chooses between it and the registry layer, and mounts the switch.
|
|
105
124
|
import {
|
|
@@ -124,7 +143,6 @@ import {
|
|
|
124
143
|
syncKeyboardPanMotion,
|
|
125
144
|
} from '../../lib/keyboard-pan'
|
|
126
145
|
import { measurementHint, parseMeasurement } from '../../lib/measurement-parser'
|
|
127
|
-
import { formatLinearMeasurement, linearUnitToMeters } from '../../lib/measurements'
|
|
128
146
|
import {
|
|
129
147
|
createGuideScaleReference,
|
|
130
148
|
formatReferenceScaleLabel,
|
|
@@ -145,7 +163,6 @@ import {
|
|
|
145
163
|
zoneAtLevelPoint,
|
|
146
164
|
} from '../../lib/units'
|
|
147
165
|
import { cn } from '../../lib/utils'
|
|
148
|
-
import { framingAnimates } from '../../lib/viewer-selection'
|
|
149
166
|
import {
|
|
150
167
|
getWallDrawVariant,
|
|
151
168
|
getWallLineKind,
|
|
@@ -174,10 +191,9 @@ import {
|
|
|
174
191
|
} from '../../lib/wall-run-snap'
|
|
175
192
|
import { snapBuildingLocalToWorldGrid } from '../../lib/world-grid-snap'
|
|
176
193
|
import { nextZoneName } from '../../lib/zone-name'
|
|
177
|
-
import { subscribeNavigationSyncPose } from '../../store/navigation-sync-pose-store'
|
|
178
194
|
import useAlignmentGuides from '../../store/use-alignment-guides'
|
|
179
195
|
import useDrawingView from '../../store/use-drawing-view'
|
|
180
|
-
import type { GuideUiState
|
|
196
|
+
import type { GuideUiState } from '../../store/use-editor'
|
|
181
197
|
import useEditor, {
|
|
182
198
|
isAngleSnapActive,
|
|
183
199
|
isMagneticSnapActive,
|
|
@@ -193,6 +209,7 @@ import useInteractionScope, {
|
|
|
193
209
|
useReshapingNode,
|
|
194
210
|
} from '../../store/use-interaction-scope'
|
|
195
211
|
import usePlacementPreview from '../../store/use-placement-preview'
|
|
212
|
+
import { placementTypingLengthOptions, usePlacementTyping } from '../../store/use-placement-typing'
|
|
196
213
|
import { expandSessionSelectionForNode } from '../../store/use-session-groups'
|
|
197
214
|
import { useStairBuildPreview } from '../../store/use-stair-build-preview'
|
|
198
215
|
import {
|
|
@@ -220,15 +237,14 @@ import { FloorplanSnapBeaconLayer } from '../editor-2d/floorplan-snap-beacon-lay
|
|
|
220
237
|
import { FloorplanWallMoveGhostLayer } from '../editor-2d/floorplan-wall-move-ghost-layer'
|
|
221
238
|
import { FloorplanDraftLayer } from '../editor-2d/renderers/floorplan-draft-layer'
|
|
222
239
|
import { FloorplanDraftMeasurement } from '../editor-2d/renderers/floorplan-draft-measurement'
|
|
223
|
-
import { FloorplanGeometryRenderer } from '../editor-2d/renderers/floorplan-geometry-renderer'
|
|
224
240
|
import { FloorplanMarqueeLayer } from '../editor-2d/renderers/floorplan-marquee-layer'
|
|
225
241
|
import { FloorplanPlacementPreviewLayer } from '../editor-2d/renderers/floorplan-placement-preview-layer'
|
|
242
|
+
import { FloorplanPlacementTypingHud } from '../editor-2d/renderers/floorplan-placement-typing-hud'
|
|
226
243
|
import {
|
|
227
244
|
FloorplanRegistryLayer,
|
|
228
245
|
RotationAngleOverlay,
|
|
229
246
|
} from '../editor-2d/renderers/floorplan-registry-layer'
|
|
230
247
|
import { FloorplanVoronoiLayer } from '../editor-2d/renderers/floorplan-voronoi-layer'
|
|
231
|
-
import { buildSvgPolylinePath, formatPolygonPath } from '../editor-2d/svg-paths'
|
|
232
248
|
import { snapToHalf } from '../tools/item/placement-math'
|
|
233
249
|
import {
|
|
234
250
|
isBoxSelectPointerSuppressed,
|
|
@@ -253,7 +269,6 @@ import {
|
|
|
253
269
|
} from '../tools/select/screen-rectangle-selection'
|
|
254
270
|
import { collectSelectableCandidateIds } from '../tools/select/select-candidates'
|
|
255
271
|
import {
|
|
256
|
-
formatAngleRadians,
|
|
257
272
|
getAngleArcToSegmentReference,
|
|
258
273
|
getAngleToSegmentReference,
|
|
259
274
|
getSegmentAngleReferenceAtPoint,
|
|
@@ -262,6 +277,7 @@ import {
|
|
|
262
277
|
chainEndJoinsExistingWall,
|
|
263
278
|
createInvisibleWallOnCurrentLevel,
|
|
264
279
|
createWallOnCurrentLevel,
|
|
280
|
+
getSegmentGridStep,
|
|
265
281
|
isSegmentLongEnough,
|
|
266
282
|
snapWallDraftPoint,
|
|
267
283
|
snapWallDraftPointDetailed,
|
|
@@ -270,25 +286,22 @@ import {
|
|
|
270
286
|
WALL_JOIN_SNAP_RADIUS,
|
|
271
287
|
type WallPlanPoint,
|
|
272
288
|
} from '../tools/wall/wall-drafting'
|
|
273
|
-
import {
|
|
289
|
+
import { formatWallDraftHeading, resolveTypedWallEnd } from '../tools/wall/wall-typed-entry'
|
|
274
290
|
import { resolveFloorplanBackgroundSelection } from './floorplan-background-selection'
|
|
275
|
-
import {
|
|
276
|
-
subscribeFloorplanCameraNavigation,
|
|
277
|
-
useFloorplanCameraSyncBridge,
|
|
278
|
-
} from './floorplan-camera-sync'
|
|
279
291
|
import {
|
|
280
292
|
canApplyFloorplanNavigationSync,
|
|
281
293
|
canZoomFloorplanDuringNavigation,
|
|
282
|
-
createFloorplanNavigationSyncScheduler,
|
|
283
|
-
type FloorplanNavigationSyncScheduler,
|
|
284
294
|
type FloorplanPresentationViewBox,
|
|
285
295
|
finalizeFloorplanNavigation,
|
|
286
296
|
flushFloorplanRotationPresentationRestore,
|
|
287
297
|
getFloorplanRotationOverscanViewBox,
|
|
288
298
|
queueFloorplanRotationPresentationRestore,
|
|
289
299
|
resolveFloorplanPresentationViewBox,
|
|
290
|
-
setFloorplanCompassRotation,
|
|
291
300
|
} from './floorplan-navigation-presentation'
|
|
301
|
+
import {
|
|
302
|
+
endFloorplanWallTypingOnCancel,
|
|
303
|
+
installFloorplanWallTypingKeys,
|
|
304
|
+
} from './floorplan-wall-typing-keys'
|
|
292
305
|
import { swallowNextClick } from './handles/use-handle-drag'
|
|
293
306
|
import { useFloorplanBackgroundPlacement } from './use-floorplan-background-placement'
|
|
294
307
|
import { useFloorplanHitTesting } from './use-floorplan-hit-testing'
|
|
@@ -4503,6 +4516,7 @@ function FloorplanLinearDraftLayer({
|
|
|
4503
4516
|
// The thickness the wall commits at, as the 3D draft shows it.
|
|
4504
4517
|
const wallDraftThickness = useWallDraftThickness(DEFAULT_WALL_THICKNESS)
|
|
4505
4518
|
const wallDraftEnd = useFloorplanDraftPreview((s) => s.wallDraftEnd)
|
|
4519
|
+
const wallTypingActive = usePlacementTyping((s) => s.isActive)
|
|
4506
4520
|
const fenceDraftEnd = useFloorplanDraftPreview((s) => s.fenceDraftEnd)
|
|
4507
4521
|
const roofDraftEnd = useFloorplanDraftPreview((s) => s.roofDraftEnd)
|
|
4508
4522
|
const roofDraftQuarterTurn = useFloorplanDraftPreview((s) => s.roofDraftQuarterTurn)
|
|
@@ -4828,6 +4842,7 @@ function FloorplanLinearDraftLayer({
|
|
|
4828
4842
|
<FloorplanDraftMeasurement
|
|
4829
4843
|
labelBackground={isDark ? '#0f172a' : '#ffffff'}
|
|
4830
4844
|
labelText={isDark ? '#e2e8f0' : '#171717'}
|
|
4845
|
+
lengthHidden={wallTypingActive}
|
|
4831
4846
|
measurement={draftWallMeasurement}
|
|
4832
4847
|
measurementStroke={measurementStroke}
|
|
4833
4848
|
sceneRotationDeg={sceneRotationDeg}
|
|
@@ -4835,6 +4850,19 @@ function FloorplanLinearDraftLayer({
|
|
|
4835
4850
|
/>
|
|
4836
4851
|
)}
|
|
4837
4852
|
|
|
4853
|
+
{wallTypingActive && isWallBuildActive && wallDraftStart ? (
|
|
4854
|
+
<FloorplanPlacementTypingHud
|
|
4855
|
+
placeholders={[
|
|
4856
|
+
draftWallMeasurement?.lengthLabel ?? '',
|
|
4857
|
+
wallDraftEnd ? formatWallDraftHeading(wallDraftStart, wallDraftEnd) : '',
|
|
4858
|
+
]}
|
|
4859
|
+
sceneRotationDeg={sceneRotationDeg}
|
|
4860
|
+
unitsPerPixel={unitsPerPixel}
|
|
4861
|
+
x={(draftWallMeasurement?.midpoint ?? wallDraftStart)[0]}
|
|
4862
|
+
y={(draftWallMeasurement?.midpoint ?? wallDraftStart)[1]}
|
|
4863
|
+
/>
|
|
4864
|
+
) : null}
|
|
4865
|
+
|
|
4838
4866
|
{polygonRoomDraft?.map((points, index) => (
|
|
4839
4867
|
<FloorplanDraftLayer
|
|
4840
4868
|
anchorFill={draftStroke}
|
|
@@ -4889,7 +4917,7 @@ const DRAFT_AXIS_GUIDE_EXTENT = 1000
|
|
|
4889
4917
|
export function FloorplanPanel({
|
|
4890
4918
|
/**
|
|
4891
4919
|
* Element to portal the compass button into. The 2D/3D navigation poses stay
|
|
4892
|
-
* in sync (`
|
|
4920
|
+
* in sync (`navigationSyncPoseStore`), so hosting the compass on the always-visible
|
|
4893
4921
|
* viewer-area container keeps it correct — needle and align-to-north alike —
|
|
4894
4922
|
* in 2d, 3d, and split modes, while this panel itself may be display:none.
|
|
4895
4923
|
*/
|
|
@@ -4912,6 +4940,9 @@ export function FloorplanPanel({
|
|
|
4912
4940
|
const floorplanSpacePanPressedRef = useRef(false)
|
|
4913
4941
|
const floorplanNavigationClickSuppressedRef = useRef(false)
|
|
4914
4942
|
const guideInteractionRef = useRef<GuideInteractionState | null>(null)
|
|
4943
|
+
// Late-bound so the window keydown effect can commit the wall draft at the
|
|
4944
|
+
// typed length without an ordering dependency on `handleWallPlacementPoint`.
|
|
4945
|
+
const wallPlacementPointRef = useRef<((point: WallPlanPoint) => void) | null>(null)
|
|
4915
4946
|
const guideTransformDraftRef = useRef<GuideTransformDraft | null>(null)
|
|
4916
4947
|
const pendingFenceDragRef = useRef<PendingFenceDragState | null>(null)
|
|
4917
4948
|
const wallEndpointDragRef = useRef<WallEndpointDragState | null>(null)
|
|
@@ -4958,7 +4989,7 @@ export function FloorplanPanel({
|
|
|
4958
4989
|
viewWidth: number
|
|
4959
4990
|
} | null>(null)
|
|
4960
4991
|
const latestNavigationSyncPoseRef = useRef<NavigationSyncPose | null>(
|
|
4961
|
-
|
|
4992
|
+
navigationSyncPoseStore.getState().pose,
|
|
4962
4993
|
)
|
|
4963
4994
|
const compassNeedleRef = useRef<SVGSVGElement | null>(null)
|
|
4964
4995
|
const hiddenCompassAnimationRef = useRef<number | null>(null)
|
|
@@ -5105,6 +5136,25 @@ export function FloorplanPanel({
|
|
|
5105
5136
|
// Walls committed by the current 2D-only chain — exclusion set for the
|
|
5106
5137
|
// T-junction chain-termination test (mirrors the 3D tool's `chainWallIds`).
|
|
5107
5138
|
const wallChainWallIdsRef = useRef<string[]>([])
|
|
5139
|
+
// Split view: the 3D wall tool owns the commit and publishes each segment's
|
|
5140
|
+
// resolved end as the chain start. Re-base this panel's draft onto it so a
|
|
5141
|
+
// typed Enter in the plan projects from the segment the 3D chain is
|
|
5142
|
+
// actually drafting — without this, `draftStart` stays on the last point
|
|
5143
|
+
// the panel itself placed and the typed commit uses a stale origin. In
|
|
5144
|
+
// 2D-only the panel is the committer and never publishes, so this
|
|
5145
|
+
// subscription stays dormant there.
|
|
5146
|
+
useEffect(() => {
|
|
5147
|
+
if (!(mode === 'build' && tool === 'wall')) return
|
|
5148
|
+
return useSegmentDraftChain.subscribe((state, previousState) => {
|
|
5149
|
+
const next = state.wall
|
|
5150
|
+
if (next === previousState.wall) return
|
|
5151
|
+
if (!next) return
|
|
5152
|
+
setDraftStart((current) =>
|
|
5153
|
+
current && current[0] === next[0] && current[1] === next[1] ? current : next,
|
|
5154
|
+
)
|
|
5155
|
+
setWallChainFirstVertex((current) => current ?? next)
|
|
5156
|
+
})
|
|
5157
|
+
}, [mode, tool])
|
|
5108
5158
|
// Direction of the run's last wall (a pulled run's source first): the next
|
|
5109
5159
|
// holds square to it. Null before the run has a wall.
|
|
5110
5160
|
const wallRunReferenceRef = useRef<WallPlanPoint | null>(null)
|
|
@@ -5115,6 +5165,8 @@ export function FloorplanPanel({
|
|
|
5115
5165
|
},
|
|
5116
5166
|
[],
|
|
5117
5167
|
)
|
|
5168
|
+
// The pointer's own (snapped) wall draft end; a typed session re-projects it.
|
|
5169
|
+
const wallDraftPointerRef = useRef<WallPlanPoint | null>(null)
|
|
5118
5170
|
const [fenceDraftStart, setFenceDraftStart] = useState<WallPlanPoint | null>(null)
|
|
5119
5171
|
const setFenceDraftEnd = useCallback(
|
|
5120
5172
|
(next: WallPlanPoint | null | ((prev: WallPlanPoint | null) => WallPlanPoint | null)) => {
|
|
@@ -7358,7 +7410,7 @@ export function FloorplanPanel({
|
|
|
7358
7410
|
)
|
|
7359
7411
|
const targetY = latestNavigationSyncPoseRef.current?.target[1] ?? floorplanGridWorldY
|
|
7360
7412
|
|
|
7361
|
-
|
|
7413
|
+
publishNavigationSyncPose({
|
|
7362
7414
|
source: '2d',
|
|
7363
7415
|
target: [worldCenter.x, targetY, worldCenter.z],
|
|
7364
7416
|
azimuth: cameraAzimuthFromFloorplanRotation(userRotationDeg),
|
|
@@ -7379,7 +7431,7 @@ export function FloorplanPanel({
|
|
|
7379
7431
|
const northAzimuth = cameraAzimuthFromFloorplanRotation(
|
|
7380
7432
|
nearestEquivalentDegrees(0, currentRotation),
|
|
7381
7433
|
)
|
|
7382
|
-
|
|
7434
|
+
publishNavigationSyncPose({
|
|
7383
7435
|
source: '2d',
|
|
7384
7436
|
target: [...pose.target],
|
|
7385
7437
|
azimuth: northAzimuth,
|
|
@@ -7916,6 +7968,26 @@ export function FloorplanPanel({
|
|
|
7916
7968
|
}
|
|
7917
7969
|
}, [isFloorplanOpen, stopFloorplanViewAnimation])
|
|
7918
7970
|
|
|
7971
|
+
// Typing reshapes the plan's own draft without a pointer move.
|
|
7972
|
+
useEffect(() => {
|
|
7973
|
+
if (!draftStart) return
|
|
7974
|
+
return usePlacementTyping.subscribe((state, previous) => {
|
|
7975
|
+
if (state.fields === previous.fields && state.isActive === previous.isActive) return
|
|
7976
|
+
const pointer = wallDraftPointerRef.current
|
|
7977
|
+
if (!pointer) return
|
|
7978
|
+
setDraftEnd(
|
|
7979
|
+
(state.isActive &&
|
|
7980
|
+
resolveTypedWallEnd(
|
|
7981
|
+
draftStart,
|
|
7982
|
+
pointer,
|
|
7983
|
+
state.fields,
|
|
7984
|
+
placementTypingLengthOptions(unit, metricNotation),
|
|
7985
|
+
getSegmentGridStep(),
|
|
7986
|
+
)) ||
|
|
7987
|
+
pointer,
|
|
7988
|
+
)
|
|
7989
|
+
})
|
|
7990
|
+
}, [draftStart, metricNotation, setDraftEnd, unit])
|
|
7919
7991
|
// Clearing an open wall draft drops a Polygon room in progress (nothing of
|
|
7920
7992
|
// it was written); paths that keep it commit first.
|
|
7921
7993
|
const clearWallPlacementDraft = useCallback(() => {
|
|
@@ -7926,6 +7998,8 @@ export function FloorplanPanel({
|
|
|
7926
7998
|
wallChainWallIdsRef.current = []
|
|
7927
7999
|
wallRunReferenceRef.current = null
|
|
7928
8000
|
setDraftEnd(null)
|
|
8001
|
+
wallDraftPointerRef.current = null
|
|
8002
|
+
usePlacementTyping.getState().clear()
|
|
7929
8003
|
useSegmentDraftChain.getState().clear('wall')
|
|
7930
8004
|
// A run pulled from a wall end ends with the plan's draft: back to Select.
|
|
7931
8005
|
endWallPullRun()
|
|
@@ -8033,6 +8107,7 @@ export function FloorplanPanel({
|
|
|
8033
8107
|
|
|
8034
8108
|
useEffect(() => {
|
|
8035
8109
|
const handleCancel = () => {
|
|
8110
|
+
if (endFloorplanWallTypingOnCancel()) return
|
|
8036
8111
|
clearDraft()
|
|
8037
8112
|
}
|
|
8038
8113
|
|
|
@@ -8042,6 +8117,20 @@ export function FloorplanPanel({
|
|
|
8042
8117
|
}
|
|
8043
8118
|
}, [clearDraft])
|
|
8044
8119
|
|
|
8120
|
+
// Split view: when the 3D wall tool stops drafting (auto-close,
|
|
8121
|
+
// T-junction, single-segment, cancel) it clears the published chain start.
|
|
8122
|
+
// That null clear must tear this panel's draft down too, or the 2D side
|
|
8123
|
+
// keeps a live draft that swallows typing keys against a chain the 3D
|
|
8124
|
+
// view already ended. Lives here (below `clearDraft`)
|
|
8125
|
+
// rather than beside the re-base subscription so the teardown stays
|
|
8126
|
+
// reachable.
|
|
8127
|
+
useEffect(() => {
|
|
8128
|
+
if (!(mode === 'build' && tool === 'wall')) return
|
|
8129
|
+
return useSegmentDraftChain.subscribe((state, previousState) => {
|
|
8130
|
+
if (state.wall === null && previousState.wall !== null) clearDraft()
|
|
8131
|
+
})
|
|
8132
|
+
}, [mode, tool, clearDraft])
|
|
8133
|
+
|
|
8045
8134
|
// A wall end's pull grip pressed in the plan opens the Walls run at that
|
|
8046
8135
|
// end: start the plan's draft there, as if the end had been clicked. A pull
|
|
8047
8136
|
// from the 3D view drafts there (the plan beside it follows its moves).
|
|
@@ -8315,6 +8404,31 @@ export function FloorplanPanel({
|
|
|
8315
8404
|
return unsubscribe
|
|
8316
8405
|
}, [movingNode, scheduleMovingFloorplanNodeRefresh])
|
|
8317
8406
|
|
|
8407
|
+
// Read by the typed-entry listener, registered once so it stays ahead of
|
|
8408
|
+
// the global shortcuts.
|
|
8409
|
+
const wallTypingSourceRef = useRef({
|
|
8410
|
+
draftStart: null as WallPlanPoint | null,
|
|
8411
|
+
lengthOptions: placementTypingLengthOptions(unit, metricNotation),
|
|
8412
|
+
})
|
|
8413
|
+
wallTypingSourceRef.current = {
|
|
8414
|
+
draftStart: isWallBuildActive ? draftStart : null,
|
|
8415
|
+
lengthOptions: placementTypingLengthOptions(unit, metricNotation),
|
|
8416
|
+
}
|
|
8417
|
+
useEffect(
|
|
8418
|
+
() =>
|
|
8419
|
+
installFloorplanWallTypingKeys({
|
|
8420
|
+
getDraft: () => {
|
|
8421
|
+
const { draftStart: start, lengthOptions } = wallTypingSourceRef.current
|
|
8422
|
+
if (!start) return null
|
|
8423
|
+
const pointer =
|
|
8424
|
+
wallDraftPointerRef.current ?? useFloorplanDraftPreview.getState().wallDraftEnd ?? start
|
|
8425
|
+
return { start, pointer, lengthOptions }
|
|
8426
|
+
},
|
|
8427
|
+
commit: (pointer) => wallPlacementPointRef.current?.(pointer),
|
|
8428
|
+
}),
|
|
8429
|
+
[],
|
|
8430
|
+
)
|
|
8431
|
+
|
|
8318
8432
|
useEffect(() => {
|
|
8319
8433
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
8320
8434
|
const target = event.target as HTMLElement | null
|
|
@@ -8393,7 +8507,16 @@ export function FloorplanPanel({
|
|
|
8393
8507
|
window.removeEventListener('keyup', handleKeyUp)
|
|
8394
8508
|
window.removeEventListener('blur', handleBlur)
|
|
8395
8509
|
}
|
|
8396
|
-
}, [
|
|
8510
|
+
}, [
|
|
8511
|
+
isFloorplanOpen,
|
|
8512
|
+
isStairBuildActive,
|
|
8513
|
+
movingNode,
|
|
8514
|
+
isWallBuildActive,
|
|
8515
|
+
draftStart,
|
|
8516
|
+
unit,
|
|
8517
|
+
metricNotation,
|
|
8518
|
+
setDraftEnd,
|
|
8519
|
+
])
|
|
8397
8520
|
|
|
8398
8521
|
useEffect(() => {
|
|
8399
8522
|
const handleWindowPointerMove = (event: PointerEvent) => {
|
|
@@ -9653,8 +9776,23 @@ export function FloorplanPanel({
|
|
|
9653
9776
|
// Emit `grid:move` so the registry-driven wall tool's 3D preview
|
|
9654
9777
|
// tracks the cursor. The local draftEnd update below is what
|
|
9655
9778
|
// drives the 2D draft polygon — both views update in parallel.
|
|
9779
|
+
// An open typed session re-projects the pointer onto what was typed;
|
|
9780
|
+
// the 3D tool gets the pointer itself and projects it the same way.
|
|
9781
|
+
wallDraftPointerRef.current = draftStart ? snappedPoint : null
|
|
9782
|
+
const wallTyping = usePlacementTyping.getState()
|
|
9783
|
+
const draftEndPoint =
|
|
9784
|
+
(draftStart &&
|
|
9785
|
+
wallTyping.isActive &&
|
|
9786
|
+
resolveTypedWallEnd(
|
|
9787
|
+
draftStart,
|
|
9788
|
+
snappedPoint,
|
|
9789
|
+
wallTyping.fields,
|
|
9790
|
+
placementTypingLengthOptions(unit, metricNotation),
|
|
9791
|
+
getSegmentGridStep(),
|
|
9792
|
+
)) ||
|
|
9793
|
+
snappedPoint
|
|
9656
9794
|
emitFloorplanGridEvent('move', snappedPoint, event)
|
|
9657
|
-
setCursorPoint(
|
|
9795
|
+
setCursorPoint(draftEndPoint)
|
|
9658
9796
|
|
|
9659
9797
|
if (!draftStart) {
|
|
9660
9798
|
return
|
|
@@ -9663,13 +9801,13 @@ export function FloorplanPanel({
|
|
|
9663
9801
|
setDraftEnd((previousEnd) => {
|
|
9664
9802
|
if (
|
|
9665
9803
|
!previousEnd ||
|
|
9666
|
-
previousEnd[0] !==
|
|
9667
|
-
previousEnd[1] !==
|
|
9804
|
+
previousEnd[0] !== draftEndPoint[0] ||
|
|
9805
|
+
previousEnd[1] !== draftEndPoint[1]
|
|
9668
9806
|
) {
|
|
9669
9807
|
sfxEmitter.emit('sfx:grid-snap')
|
|
9670
9808
|
}
|
|
9671
9809
|
|
|
9672
|
-
return
|
|
9810
|
+
return draftEndPoint
|
|
9673
9811
|
})
|
|
9674
9812
|
},
|
|
9675
9813
|
[
|
|
@@ -9704,6 +9842,11 @@ export function FloorplanPanel({
|
|
|
9704
9842
|
isRoofBuildActive,
|
|
9705
9843
|
isWallBuildActive,
|
|
9706
9844
|
levelId,
|
|
9845
|
+
// `unit` / `metricNotation` feed the typed-length projection helpers
|
|
9846
|
+
// shared with the commit path; listed so a unit change re-binds the
|
|
9847
|
+
// move preview to the new bare-unit parse.
|
|
9848
|
+
metricNotation,
|
|
9849
|
+
unit,
|
|
9707
9850
|
publishFloorplanNavigationPose,
|
|
9708
9851
|
referenceScaleDraft,
|
|
9709
9852
|
siteVertexDragState,
|
|
@@ -9889,7 +10032,21 @@ export function FloorplanPanel({
|
|
|
9889
10032
|
)
|
|
9890
10033
|
|
|
9891
10034
|
const handleWallPlacementPoint = useCallback(
|
|
9892
|
-
(
|
|
10035
|
+
(rawPoint: WallPlanPoint) => {
|
|
10036
|
+
// An open typed session commits what its preview shows: the pointer
|
|
10037
|
+
// re-projected onto what was typed, never re-snapped.
|
|
10038
|
+
const typing = usePlacementTyping.getState()
|
|
10039
|
+
const typedEnd =
|
|
10040
|
+
draftStart && typing.isActive
|
|
10041
|
+
? resolveTypedWallEnd(
|
|
10042
|
+
draftStart,
|
|
10043
|
+
rawPoint,
|
|
10044
|
+
typing.fields,
|
|
10045
|
+
placementTypingLengthOptions(unit, metricNotation),
|
|
10046
|
+
getSegmentGridStep(),
|
|
10047
|
+
)
|
|
10048
|
+
: null
|
|
10049
|
+
const point: WallPlanPoint = typedEnd ?? rawPoint
|
|
9893
10050
|
if (!draftStart) {
|
|
9894
10051
|
wallConstructionOptionsRef.current = levelId
|
|
9895
10052
|
? resolveTerrainWallConstructionOptions(
|
|
@@ -9950,6 +10107,7 @@ export function FloorplanPanel({
|
|
|
9950
10107
|
setDraftStart(point)
|
|
9951
10108
|
setDraftEnd(point)
|
|
9952
10109
|
setCursorPoint(point)
|
|
10110
|
+
usePlacementTyping.getState().clear()
|
|
9953
10111
|
return
|
|
9954
10112
|
}
|
|
9955
10113
|
if (viewIs2DOnly) {
|
|
@@ -10015,16 +10173,26 @@ export function FloorplanPanel({
|
|
|
10015
10173
|
setDraftStart(nextStart)
|
|
10016
10174
|
setDraftEnd(nextStart)
|
|
10017
10175
|
setCursorPoint(nextStart)
|
|
10176
|
+
// What was typed belongs to this segment; the next starts afresh.
|
|
10177
|
+
usePlacementTyping.getState().clear()
|
|
10018
10178
|
},
|
|
10019
10179
|
[
|
|
10020
10180
|
clearWallPlacementDraft,
|
|
10021
10181
|
draftStart,
|
|
10022
10182
|
levelId,
|
|
10183
|
+
metricNotation,
|
|
10184
|
+
unit,
|
|
10023
10185
|
wallChainFirstVertex,
|
|
10024
10186
|
setDraftEnd,
|
|
10025
10187
|
setCursorPoint,
|
|
10026
10188
|
],
|
|
10027
10189
|
)
|
|
10190
|
+
// Latest-ref for the Enter-commit path: assigning the ref inside the
|
|
10191
|
+
// callback itself froze the first-render closure (draftStart === null), so
|
|
10192
|
+
// a typed Enter re-started the draft instead of committing the wall.
|
|
10193
|
+
useEffect(() => {
|
|
10194
|
+
wallPlacementPointRef.current = handleWallPlacementPoint
|
|
10195
|
+
}, [handleWallPlacementPoint])
|
|
10028
10196
|
const { getFloorplanHitIdAtPoint, getFloorplanSelectionIdsInBounds } = useFloorplanHitTesting({
|
|
10029
10197
|
sceneRef: floorplanSceneRef,
|
|
10030
10198
|
})
|
|
@@ -10254,6 +10422,7 @@ export function FloorplanPanel({
|
|
|
10254
10422
|
unit,
|
|
10255
10423
|
emitFloorplanGridEvent,
|
|
10256
10424
|
setCursorPoint,
|
|
10425
|
+
locale,
|
|
10257
10426
|
],
|
|
10258
10427
|
)
|
|
10259
10428
|
const handleSvgClick = useCallback(
|