@pascal-app/editor 1.0.6 → 1.0.7
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 +18 -15
- package/src/components/editor/action-menu-button.tsx +4 -1
- package/src/components/editor/alignment-3d-guide-layer.tsx +102 -11
- package/src/components/editor/bake-thumbnail.tsx +3 -2
- package/src/components/editor/custom-camera-controls.tsx +20 -8
- package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
- package/src/components/editor/first-person-controls.tsx +72 -61
- package/src/components/editor/floating-action-menu.tsx +27 -9
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floorplan-panel.test.ts +220 -0
- package/src/components/editor/floorplan-panel.tsx +285 -132
- package/src/components/editor/footprint-height-handle.tsx +1 -1
- package/src/components/editor/grid.tsx +24 -15
- package/src/components/editor/group-actions.ts +19 -1
- package/src/components/editor/group-floating-action-menu.tsx +1 -1
- package/src/components/editor/group-move-3d.ts +27 -2
- package/src/components/editor/group-selection-box-3d.tsx +4 -1
- package/src/components/editor/group-transform-shared.ts +20 -0
- package/src/components/editor/index.tsx +130 -20
- package/src/components/editor/inspector-extension-actions.tsx +36 -0
- package/src/components/editor/localized-html.tsx +22 -0
- package/src/components/editor/node-action-menu.tsx +46 -12
- package/src/components/editor/node-arrow-handles.tsx +1 -2
- package/src/components/editor/open-wall-ends-3d-layer.tsx +1 -1
- package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
- package/src/components/editor/registry-action-contributions.test.tsx +67 -6
- package/src/components/editor/registry-action-contributions.tsx +115 -15
- package/src/components/editor/riser-diagram-panel.tsx +59 -9
- package/src/components/editor/room-controls.tsx +1 -1
- package/src/components/editor/room-handles-2d.tsx +156 -6
- package/src/components/editor/room-handles.tsx +241 -51
- package/src/components/editor/room-highlight.tsx +2 -0
- package/src/components/editor/room-labels.tsx +29 -15
- package/src/components/editor/selection-manager.tsx +15 -102
- package/src/components/editor/separator-end-grip.tsx +74 -0
- package/src/components/editor/site-edge-labels.tsx +1 -1
- package/src/components/editor/thumbnail-generator.test.ts +15 -6
- package/src/components/editor/thumbnail-generator.tsx +26 -1
- package/src/components/editor/use-floorplan-background-placement.ts +55 -52
- package/src/components/editor/views/view-bar.tsx +111 -26
- package/src/components/editor/wall-measurement-label.tsx +1 -1
- package/src/components/editor/wall-move-side-handles.tsx +5 -1
- package/src/components/editor/wall-pull-grip.tsx +193 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +81 -1
- package/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts +76 -0
- package/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx +186 -0
- package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +63 -3
- package/src/components/editor-2d/floorplan-group-move.tsx +31 -3
- package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +6 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +22 -13
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +11 -3
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +7 -1
- package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +96 -4
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +52 -12
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +12 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +197 -37
- package/src/components/procedural-items/inspector.tsx +59 -12
- package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +2 -0
- package/src/components/systems/ceiling/ceiling-system.test.ts +141 -0
- package/src/components/systems/ceiling/ceiling-system.tsx +53 -18
- package/src/components/tools/distribution/distribution-run-tool.tsx +50 -26
- package/src/components/tools/item/placement-history.test.tsx +1 -1
- package/src/components/tools/item/placement-strategies.test.ts +64 -1
- package/src/components/tools/item/placement-strategies.ts +5 -9
- package/src/components/tools/item/use-placement-coordinator.tsx +30 -34
- package/src/components/tools/registry/item-surface-move.test.ts +11 -0
- package/src/components/tools/select/select-candidates.test.ts +45 -0
- package/src/components/tools/select/select-candidates.ts +13 -2
- package/src/components/tools/shared/cursor-sphere.tsx +10 -3
- package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
- package/src/components/tools/shared/placement-box.tsx +1 -1
- package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
- package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
- package/src/components/tools/wall/wall-drafting.test.ts +299 -23
- package/src/components/tools/wall/wall-drafting.ts +132 -24
- package/src/components/tools/wall/wall-pull-snap.test.ts +274 -0
- package/src/components/tools/wall/wall-pull-snap.ts +563 -0
- package/src/components/tools/wall/wall-snap-geometry.test.ts +113 -1
- package/src/components/tools/wall/wall-snap-geometry.ts +137 -0
- package/src/components/tools/zone/zone-tool.tsx +3 -3
- package/src/components/ui/action-menu/action-button.tsx +2 -0
- package/src/components/ui/action-menu/camera-actions.tsx +8 -7
- package/src/components/ui/action-menu/control-modes.tsx +9 -5
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +3 -1
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +7 -1
- package/src/components/ui/action-menu/furnish-tools.tsx +7 -6
- package/src/components/ui/action-menu/index.tsx +1 -0
- package/src/components/ui/action-menu/measurement-control.tsx +35 -29
- package/src/components/ui/action-menu/point-ask-button.tsx +4 -3
- package/src/components/ui/action-menu/structure-tools.tsx +25 -23
- package/src/components/ui/action-menu/view-toggles.test.ts +18 -0
- package/src/components/ui/action-menu/view-toggles.tsx +256 -51
- package/src/components/ui/build-panel/build-panel.tsx +163 -25
- package/src/components/ui/command-palette/editor-commands.tsx +38 -11
- package/src/components/ui/controls/finish-swatch.tsx +45 -19
- package/src/components/ui/controls/material-picker.tsx +24 -17
- package/src/components/ui/controls/metric-control.test.ts +52 -0
- package/src/components/ui/controls/metric-control.tsx +62 -24
- package/src/components/ui/controls/segmented-control.tsx +5 -2
- package/src/components/ui/controls/slider-control.test.tsx +23 -0
- package/src/components/ui/controls/slider-control.tsx +30 -14
- package/src/components/ui/floating-level-selector.tsx +100 -48
- package/src/components/ui/helpers/building-helper.tsx +5 -3
- package/src/components/ui/helpers/contextual-helper-panel.tsx +97 -37
- package/src/components/ui/helpers/helper-manager.test.tsx +53 -3
- package/src/components/ui/helpers/helper-manager.tsx +82 -57
- package/src/components/ui/helpers/item-helper.tsx +6 -4
- package/src/components/ui/helpers/registered-tool-helper.tsx +3 -1
- package/src/components/ui/level-duplicate-dialog.tsx +32 -23
- package/src/components/ui/level-wall-copy-prompt.tsx +124 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +11 -11
- package/src/components/ui/panels/deck-boards-fields.tsx +136 -0
- package/src/components/ui/panels/floor-foundation-panel.tsx +113 -38
- package/src/components/ui/panels/floor-opening-panel.tsx +73 -25
- package/src/components/ui/panels/inspector-extensions.tsx +66 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +3 -1
- package/src/components/ui/panels/mobile-selection-bar.tsx +8 -6
- package/src/components/ui/panels/multi-field-value.test.ts +27 -0
- package/src/components/ui/panels/multi-field-value.ts +20 -1
- package/src/components/ui/panels/multi-height-mode.tsx +8 -7
- package/src/components/ui/panels/multi-parametric-inspector.tsx +122 -34
- package/src/components/ui/panels/multi-selection-panel.tsx +75 -35
- package/src/components/ui/panels/node-display.ts +35 -24
- package/src/components/ui/panels/panel-manager.tsx +5 -3
- package/src/components/ui/panels/panel-wrapper.tsx +22 -109
- package/src/components/ui/panels/parametric-field-control.tsx +13 -10
- package/src/components/ui/panels/parametric-inspector.tsx +18 -12
- package/src/components/ui/panels/reference-panel.tsx +51 -35
- package/src/components/ui/panels/room-construction-rows.tsx +464 -65
- package/src/components/ui/panels/room-name-options.test.ts +36 -3
- package/src/components/ui/panels/room-name-options.ts +110 -11
- package/src/components/ui/panels/room-openings-field.tsx +21 -12
- package/src/components/ui/panels/room-panel.tsx +206 -99
- package/src/components/ui/panels/shape-choice.tsx +7 -5
- package/src/components/ui/panels/wall-region-list.tsx +7 -7
- package/src/components/ui/primitives/shortcut-token.tsx +10 -6
- package/src/components/ui/sidebar/icon-rail.tsx +11 -9
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +10 -10
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +10 -9
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +3 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +102 -32
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +7 -5
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/default-names.ts +75 -0
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +117 -64
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +36 -3
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +7 -4
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +8 -2
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +8 -5
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +8 -3
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +8 -7
- package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +7 -6
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +16 -1
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +15 -8
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +3 -1
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +18 -8
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +25 -14
- package/src/components/ui/sidebar/tab-bar.tsx +4 -1
- package/src/components/ui/sidebar/use-plugin-panels.tsx +19 -10
- package/src/components/ui/snap-target-badge.tsx +7 -6
- package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +721 -0
- package/src/components/ui/wall-type/wall-type-menu.tsx +167 -0
- package/src/components/viewer/floorplan-compass-button.tsx +12 -3
- package/src/components/viewer/floorplan-preview.tsx +27 -19
- package/src/components/viewer/render-settings-menu.tsx +294 -0
- package/src/components/viewer/sky-control.tsx +710 -0
- package/src/components/viewer/use-viewer-ui-sounds.test.ts +15 -0
- package/src/components/viewer/use-viewer-ui-sounds.ts +46 -0
- package/src/components/viewer/viewer-controls-bar.tsx +278 -260
- package/src/components/viewer/viewer-hover-label.tsx +12 -4
- package/src/components/viewer/viewer-rooms.tsx +61 -4
- package/src/components/viewer/viewer-scene-header.tsx +28 -17
- package/src/components/viewer/viewer-stage-switcher.tsx +4 -2
- package/src/components/viewer-overlay.tsx +8 -0
- package/src/components/walkthrough-hud.tsx +75 -2
- package/src/hooks/use-keyboard.test.ts +85 -4
- package/src/hooks/use-keyboard.ts +65 -7
- package/src/hooks/use-selected-room.ts +12 -1
- package/src/i18n/floor-footprint-name.ts +30 -0
- package/src/i18n/level-name.ts +39 -0
- package/src/i18n/locales/en/messages.po +15117 -0
- package/src/i18n/locales/en/messages.ts +1 -0
- package/src/i18n/locales/en-XA/messages.ts +1 -0
- package/src/i18n/locales/es/messages.po +37501 -0
- package/src/i18n/locales/es/messages.ts +1 -0
- package/src/i18n/locales/fr/messages.po +37501 -0
- package/src/i18n/locales/fr/messages.ts +1 -0
- package/src/i18n/locales/ja/messages.po +37501 -0
- package/src/i18n/locales/ja/messages.ts +1 -0
- package/src/i18n/locales/zh-CN/messages.po +37501 -0
- package/src/i18n/locales/zh-CN/messages.ts +1 -0
- package/src/i18n/locales.test.ts +63 -0
- package/src/i18n/locales.ts +32 -0
- package/src/i18n/message-slot.tsx +25 -0
- package/src/i18n/node-messages.ts +169 -0
- package/src/i18n/pseudo-locale.ts +17 -0
- package/src/i18n/published-entry.test.ts +17 -0
- package/src/i18n/scene-theme-name.ts +16 -0
- package/src/index.tsx +156 -4
- package/src/lib/add-storey.test.ts +3 -3
- package/src/lib/contextual-help.test.ts +20 -1
- package/src/lib/contextual-help.ts +95 -19
- package/src/lib/continuation.ts +38 -11
- package/src/lib/floor-footprints.test.ts +2 -1
- package/src/lib/floor-foundation-support.test.ts +7 -3
- package/src/lib/floorplan/dimension-drive.test.ts +36 -2
- package/src/lib/floorplan/dimension-drive.ts +68 -3
- package/src/lib/floorplan/floorplan-export.test.ts +16 -5
- package/src/lib/floorplan/floorplan-export.tsx +13 -16
- package/src/lib/floorplan/floorplan-extension.test.ts +11 -12
- package/src/lib/floorplan/floorplan-extension.ts +37 -18
- package/src/lib/floorplan/floorplan-mode.test.ts +13 -6
- package/src/lib/floorplan/floorplan-mode.ts +14 -12
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +1 -1
- package/src/lib/floorplan/floorplan-readonly.ts +3 -3
- package/src/lib/floorplan/schedules.ts +10 -6
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +46 -1
- package/src/lib/floorplan/site-plan/site-annotations.ts +3 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +6 -3
- package/src/lib/geometry-script/author.test.ts +114 -0
- package/src/lib/geometry-script/author.ts +55 -23
- package/src/lib/geometry-script/client.ts +3 -0
- package/src/lib/geometry-script/finish-scripts.ts +7 -7
- package/src/lib/glb-export.test.ts +327 -0
- package/src/lib/glb-export.ts +70 -2
- package/src/lib/grid-frame.test.ts +56 -3
- package/src/lib/grid-frame.ts +28 -1
- package/src/lib/history.test.ts +2 -1
- package/src/lib/hud-title.ts +48 -24
- package/src/lib/ifc-export.test.ts +41 -1
- package/src/lib/inspector-card-mode.test.ts +3 -31
- package/src/lib/inspector-card-mode.ts +5 -10
- package/src/lib/inspector-expanded.test.ts +13 -0
- package/src/lib/inspector-expanded.ts +13 -1
- package/src/lib/keyboard-pan.test.ts +7 -0
- package/src/lib/keyboard-pan.ts +9 -2
- package/src/lib/layer-thickness.test.ts +22 -0
- package/src/lib/layer-thickness.ts +79 -0
- package/src/lib/lot/drop-in.test.ts +59 -1
- package/src/lib/lot/drop-in.ts +42 -50
- package/src/lib/material-swatch-style.ts +24 -0
- package/src/lib/measurement-parser.ts +7 -3
- package/src/lib/measurements.test.ts +17 -0
- package/src/lib/measurements.ts +20 -5
- package/src/lib/mezzanine-selection.test.ts +3 -1
- package/src/lib/orbit-near-plane.test.ts +12 -0
- package/src/lib/orbit-near-plane.ts +13 -0
- package/src/lib/paint-regions.test.ts +8 -5
- package/src/lib/paint-scope.test.ts +53 -0
- package/src/lib/paint-scope.ts +18 -4
- package/src/lib/panel-rows.ts +17 -8
- package/src/lib/reference-scale.ts +83 -0
- package/src/lib/room-built-on.test.ts +26 -12
- package/src/lib/room-built-on.ts +20 -2
- package/src/lib/room-construction.test.ts +28 -1
- package/src/lib/room-construction.ts +14 -0
- package/src/lib/room-controls-phase6.test.ts +140 -0
- package/src/lib/room-handle-drag.ts +557 -42
- package/src/lib/room-name-catalog.test.ts +8 -0
- package/src/lib/room-name-catalog.ts +8 -1
- package/src/lib/room-name-messages.test.ts +132 -0
- package/src/lib/room-name-messages.ts +147 -0
- package/src/lib/room-name-storage.test.ts +334 -0
- package/src/lib/room-push-dimensions.test.ts +37 -0
- package/src/lib/room-push-dimensions.ts +226 -2
- package/src/lib/room-selection.test.ts +23 -6
- package/src/lib/scene-clipboard.test.ts +70 -49
- package/src/lib/scene-clipboard.ts +9 -4
- package/src/lib/selection-cycle.ts +63 -0
- package/src/lib/separator-edit.test.ts +431 -0
- package/src/lib/separator-edit.ts +179 -0
- package/src/lib/separator-lines.ts +38 -0
- package/src/lib/sfx-bus.ts +27 -1
- package/src/lib/sfx-player.ts +16 -0
- package/src/lib/tool-cursor-icon.ts +5 -1
- package/src/lib/tool-shortcuts.ts +130 -0
- package/src/lib/viewer-selection.test.ts +28 -24
- package/src/lib/viewer-selection.ts +20 -5
- package/src/lib/wall-draw-variant.test.ts +7 -6
- package/src/lib/wall-draw-variant.ts +107 -6
- package/src/lib/wall-nudge.test.ts +44 -0
- package/src/lib/wall-nudge.ts +131 -0
- package/src/lib/wall-parallel-snap.test.ts +83 -0
- package/src/lib/wall-parallel-snap.ts +176 -0
- package/src/lib/wall-placement-pointer.test.ts +23 -0
- package/src/lib/wall-placement-pointer.ts +18 -0
- package/src/lib/wall-pull.test.ts +245 -0
- package/src/lib/wall-pull.ts +209 -0
- package/src/lib/wall-push-line-up.test.ts +132 -0
- package/src/lib/wall-region-list.ts +14 -5
- package/src/lib/wall-run-snap.test.ts +188 -0
- package/src/lib/wall-run-snap.ts +83 -0
- package/src/lib/wall-type.test.ts +125 -0
- package/src/lib/wall-type.ts +119 -0
- package/src/lib/window-interaction.test.ts +42 -0
- package/src/lib/window-interaction.ts +47 -5
- package/src/lib/world-grid-snap.test.ts +139 -2
- package/src/lib/world-grid-snap.ts +102 -105
- package/src/store/use-alignment-guides.ts +27 -1
- package/src/store/use-editor.tsx +48 -0
- package/src/store/use-floorplan-annotation-visibility.test.ts +64 -0
- package/src/store/use-floorplan-annotation-visibility.ts +47 -22
- package/src/store/use-wall-snap-indicator.ts +15 -2
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
type AnyNodeId,
|
|
4
5
|
clampRoomFloorHandle,
|
|
5
6
|
type Point,
|
|
6
7
|
roomDrawnFloor,
|
|
7
8
|
sceneRegistry,
|
|
9
|
+
usePascalI18n,
|
|
8
10
|
useScene,
|
|
9
11
|
} from '@pascal-app/core'
|
|
10
12
|
import { useViewer } from '@pascal-app/viewer'
|
|
11
|
-
import { Html } from '@react-three/drei'
|
|
12
13
|
import { type ThreeEvent, useFrame, useThree } from '@react-three/fiber'
|
|
13
14
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
14
15
|
import {
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
publishStructuralElevationGuide,
|
|
34
35
|
resolveStructuralElevationSnap,
|
|
35
36
|
} from '../../lib/elevation-guides'
|
|
37
|
+
import { parseDimensionInput } from '../../lib/floorplan/dimension-drive'
|
|
36
38
|
import { formatLinearMeasurement, MEASUREMENT_ACTIVE_COLOR } from '../../lib/measurements'
|
|
37
39
|
import { commitRoomFloorElevation, roomFloorBase } from '../../lib/room-construction-commands'
|
|
38
40
|
import {
|
|
@@ -51,10 +53,16 @@ import {
|
|
|
51
53
|
import type { RoomDimension } from '../../lib/room-push-dimensions'
|
|
52
54
|
import type { RoomSelectionRecord } from '../../lib/room-selection'
|
|
53
55
|
import useEditor, { isGridSnapActive, isMagneticSnapActive } from '../../store/use-editor'
|
|
56
|
+
import {
|
|
57
|
+
commitDimensionValue,
|
|
58
|
+
useDimensionEditAllowed,
|
|
59
|
+
} from '../editor-2d/renderers/floorplan-dimension-edit-overlay'
|
|
54
60
|
import { suppressBoxSelectForPointer } from '../tools/select/box-select-state'
|
|
55
61
|
import { ARROW_COLOR, ARROW_SCALE, HandleArrow } from './handles/handle-arrow'
|
|
56
62
|
import { resolveResizeSnapValue } from './handles/resize-snap'
|
|
63
|
+
import { Html } from './localized-html'
|
|
57
64
|
import { formatMeasurement } from './measurement-pill'
|
|
65
|
+
import { useSelectedWallDimensions } from './room-handles-2d'
|
|
58
66
|
import { WallPushArrow } from './wall-push-arrow'
|
|
59
67
|
|
|
60
68
|
const PILL =
|
|
@@ -295,8 +303,9 @@ export function ElevationArrows({
|
|
|
295
303
|
|
|
296
304
|
/**
|
|
297
305
|
* A selected room's 3D handles: the floor elevation tracker at its centroid
|
|
298
|
-
* and one push/pull arrow outside every boundary wall
|
|
299
|
-
* frame by `RoomControls3D`, only
|
|
306
|
+
* and one push/pull arrow outside every boundary wall and every straight edge
|
|
307
|
+
* of invisible walls. Rendered in the level frame by `RoomControls3D`, only
|
|
308
|
+
* while nothing else is in progress.
|
|
300
309
|
*/
|
|
301
310
|
export function RoomHandles3D({ room }: { room: RoomSelectionRecord }) {
|
|
302
311
|
const nodes = useScene((s) => s.nodes)
|
|
@@ -307,7 +316,11 @@ export function RoomHandles3D({ room }: { room: RoomSelectionRecord }) {
|
|
|
307
316
|
() => outlineCentroid([room.polygon as Point[], ...(room.holes as Point[][])]),
|
|
308
317
|
[room.polygon, room.holes],
|
|
309
318
|
)
|
|
310
|
-
|
|
319
|
+
// Its invisible walls' arrows lie on its floor, where their dashed lines are drawn.
|
|
320
|
+
const handles = useMemo(
|
|
321
|
+
() => roomPushHandles(nodes, room.spans, elevation),
|
|
322
|
+
[nodes, room.spans, elevation],
|
|
323
|
+
)
|
|
311
324
|
// A mezzanine has no walls: its plate edges carry the push arrows instead.
|
|
312
325
|
const edges = useMemo(
|
|
313
326
|
() => (room.mezzanine ? mezzanineEdgeHandles(nodes, room.zoneId) : []),
|
|
@@ -414,9 +427,20 @@ const DIMENSION_LABEL_OUTLINE = [
|
|
|
414
427
|
* above its room's floor and drawn over the walls, closed by cross ticks, with
|
|
415
428
|
* the measurement's outlined label — apart from the moved-distance pill.
|
|
416
429
|
*/
|
|
417
|
-
function RoomDimensionLines3D({
|
|
430
|
+
function RoomDimensionLines3D({
|
|
431
|
+
dimensions,
|
|
432
|
+
hidden = false,
|
|
433
|
+
}: {
|
|
434
|
+
/** With an `ownerId` (a selected wall's), a value can be typed to move that wall. */
|
|
435
|
+
dimensions: readonly (RoomDimension & { ownerId?: string })[]
|
|
436
|
+
/** Hides the labels while keeping their drei `Html` roots mounted. */
|
|
437
|
+
hidden?: boolean
|
|
438
|
+
}) {
|
|
439
|
+
const i18n = usePascalI18n()
|
|
418
440
|
const unit = useViewer((s) => s.unit)
|
|
419
441
|
const metricNotation = useViewer((s) => s.metricNotation)
|
|
442
|
+
const editAllowed = useDimensionEditAllowed()
|
|
443
|
+
const [editing, setEditing] = useState<string | null>(null)
|
|
420
444
|
const geometry = useMemo(() => {
|
|
421
445
|
if (!dimensions.length) return null
|
|
422
446
|
const positions: number[] = []
|
|
@@ -441,27 +465,175 @@ function RoomDimensionLines3D({ dimensions }: { dimensions: RoomDimension[] }) {
|
|
|
441
465
|
raycast={noRaycast}
|
|
442
466
|
renderOrder={1001}
|
|
443
467
|
/>
|
|
444
|
-
{dimensions.map((dimension) =>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
className="-translate-y-3 whitespace-nowrap font-medium text-base text-white"
|
|
458
|
-
data-room-dimension-3d
|
|
459
|
-
style={{ textShadow: DIMENSION_LABEL_OUTLINE }}
|
|
468
|
+
{dimensions.map(({ ownerId: wallId, ...dimension }) => {
|
|
469
|
+
const editable = editAllowed && !!wallId
|
|
470
|
+
return (
|
|
471
|
+
<Html
|
|
472
|
+
center
|
|
473
|
+
key={dimension.key}
|
|
474
|
+
position={[
|
|
475
|
+
(dimension.from[0] + dimension.to[0]) / 2,
|
|
476
|
+
dimension.elevation,
|
|
477
|
+
(dimension.from[1] + dimension.to[1]) / 2,
|
|
478
|
+
]}
|
|
479
|
+
style={{ display: hidden ? 'none' : undefined, pointerEvents: 'none' }}
|
|
480
|
+
zIndexRange={[20, 0]}
|
|
460
481
|
>
|
|
461
|
-
{
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
482
|
+
{editable && wallId && !hidden && editing === dimension.key ? (
|
|
483
|
+
<DimensionValueInput
|
|
484
|
+
dimension={dimension}
|
|
485
|
+
initial={formatMeasurement(dimension.distance, unit, metricNotation)}
|
|
486
|
+
onClose={() => setEditing(null)}
|
|
487
|
+
unit={unit}
|
|
488
|
+
wallId={wallId}
|
|
489
|
+
/>
|
|
490
|
+
) : (
|
|
491
|
+
<div
|
|
492
|
+
className={`-translate-y-3 whitespace-nowrap font-medium text-base text-white ${editable ? 'pointer-events-auto cursor-text' : ''}`}
|
|
493
|
+
data-room-dimension-3d
|
|
494
|
+
onClick={editable ? () => setEditing(dimension.key) : undefined}
|
|
495
|
+
onKeyDown={
|
|
496
|
+
editable
|
|
497
|
+
? (event) => {
|
|
498
|
+
if (event.key === 'Enter') setEditing(dimension.key)
|
|
499
|
+
}
|
|
500
|
+
: undefined
|
|
501
|
+
}
|
|
502
|
+
onPointerDown={editable ? (event) => event.stopPropagation() : undefined}
|
|
503
|
+
role={editable ? 'button' : undefined}
|
|
504
|
+
style={{ textShadow: DIMENSION_LABEL_OUTLINE }}
|
|
505
|
+
tabIndex={editable ? 0 : undefined}
|
|
506
|
+
title={
|
|
507
|
+
editable
|
|
508
|
+
? i18n._({
|
|
509
|
+
id: 'editor.roomHandles.typeASizeToMoveThe',
|
|
510
|
+
message: 'Type a size to move the wall',
|
|
511
|
+
})
|
|
512
|
+
: undefined
|
|
513
|
+
}
|
|
514
|
+
>
|
|
515
|
+
{formatMeasurement(dimension.distance, unit, metricNotation)}
|
|
516
|
+
</div>
|
|
517
|
+
)}
|
|
518
|
+
</Html>
|
|
519
|
+
)
|
|
520
|
+
})}
|
|
521
|
+
</group>
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* A temporary dimension's value, typed: Enter moves the selected wall so the
|
|
527
|
+
* dimension reads it (`commitDimensionValue`, one undo step), Esc or a click
|
|
528
|
+
* away leaves it. Feet-inches, metric and bare numbers parse as in the plan.
|
|
529
|
+
*/
|
|
530
|
+
function DimensionValueInput({
|
|
531
|
+
dimension,
|
|
532
|
+
initial,
|
|
533
|
+
onClose,
|
|
534
|
+
unit,
|
|
535
|
+
wallId,
|
|
536
|
+
}: {
|
|
537
|
+
dimension: RoomDimension
|
|
538
|
+
initial: string
|
|
539
|
+
onClose: () => void
|
|
540
|
+
unit: 'metric' | 'imperial'
|
|
541
|
+
wallId: string
|
|
542
|
+
}) {
|
|
543
|
+
const i18n = usePascalI18n()
|
|
544
|
+
const [draft, setDraft] = useState(initial)
|
|
545
|
+
const [error, setError] = useState<string | null>(null)
|
|
546
|
+
const commit = () => {
|
|
547
|
+
const nextLength = parseDimensionInput(draft, unit)
|
|
548
|
+
if (nextLength === null) {
|
|
549
|
+
setError(
|
|
550
|
+
i18n._({
|
|
551
|
+
id: 'editor.roomHandles.cannotReadInput',
|
|
552
|
+
message: 'Cannot read "{input}"',
|
|
553
|
+
values: { input: draft.trim() },
|
|
554
|
+
}),
|
|
555
|
+
)
|
|
556
|
+
return
|
|
557
|
+
}
|
|
558
|
+
const outcome = commitDimensionValue({
|
|
559
|
+
target: {
|
|
560
|
+
ownerNodeId: wallId as AnyNodeId,
|
|
561
|
+
witnessStart: dimension.from,
|
|
562
|
+
witnessEnd: dimension.to,
|
|
563
|
+
value: dimension.distance,
|
|
564
|
+
},
|
|
565
|
+
nextLength,
|
|
566
|
+
unit,
|
|
567
|
+
})
|
|
568
|
+
if (outcome.ok) onClose()
|
|
569
|
+
else setError(outcome.reason)
|
|
570
|
+
}
|
|
571
|
+
return (
|
|
572
|
+
<div
|
|
573
|
+
className="pointer-events-auto -translate-y-3 w-24"
|
|
574
|
+
onPointerDown={(event) => event.stopPropagation()}
|
|
575
|
+
>
|
|
576
|
+
<input
|
|
577
|
+
// biome-ignore lint/a11y/noAutofocus: the box opens on a click to be typed in
|
|
578
|
+
autoFocus
|
|
579
|
+
aria-label={i18n._({ id: 'editor.roomHandles.dimensionValue', message: 'Dimension value' })}
|
|
580
|
+
className="w-full rounded-sm border border-primary bg-card px-1 py-0.5 text-center font-mono text-foreground text-xs shadow-sm outline-none"
|
|
581
|
+
onBlur={onClose}
|
|
582
|
+
onChange={(event) => {
|
|
583
|
+
setDraft(event.target.value)
|
|
584
|
+
setError(null)
|
|
585
|
+
}}
|
|
586
|
+
onFocus={(event) => event.target.select()}
|
|
587
|
+
onKeyDown={(event) => {
|
|
588
|
+
event.stopPropagation()
|
|
589
|
+
if (event.key === 'Enter') {
|
|
590
|
+
event.preventDefault()
|
|
591
|
+
commit()
|
|
592
|
+
} else if (event.key === 'Escape') {
|
|
593
|
+
event.preventDefault()
|
|
594
|
+
onClose()
|
|
595
|
+
}
|
|
596
|
+
}}
|
|
597
|
+
spellCheck={false}
|
|
598
|
+
value={draft}
|
|
599
|
+
/>
|
|
600
|
+
{error ? (
|
|
601
|
+
<div className="mt-0.5 whitespace-nowrap rounded-sm bg-card px-1 text-[10px] text-destructive shadow-sm">
|
|
602
|
+
{error}
|
|
603
|
+
</div>
|
|
604
|
+
) : null}
|
|
605
|
+
</div>
|
|
606
|
+
)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* The selected walls' temporary dimensions in 3D, the plan's twin
|
|
611
|
+
* (`SelectedWallDimensions2D`): the room widths their pushes show and the
|
|
612
|
+
* outside sizes, drawn as the push draws them, in the walls' level frame.
|
|
613
|
+
*/
|
|
614
|
+
export function SelectedWallDimensions3D() {
|
|
615
|
+
const selection = useSelectedWallDimensions()
|
|
616
|
+
const isFloorplanHovered = useEditor((s) => s.isFloorplanHovered)
|
|
617
|
+
const levelId = selection?.levelId ?? null
|
|
618
|
+
const root = useRef<Group>(null)
|
|
619
|
+
useFrame(() => {
|
|
620
|
+
const level = levelId ? sceneRegistry.nodes.get(levelId) : null
|
|
621
|
+
if (!root.current) return
|
|
622
|
+
root.current.visible = !!level && !isFloorplanHovered
|
|
623
|
+
if (level) {
|
|
624
|
+
level.updateWorldMatrix(true, false)
|
|
625
|
+
root.current.matrix.copy(level.matrixWorld)
|
|
626
|
+
}
|
|
627
|
+
})
|
|
628
|
+
// The labels are DOM (drei `Html`); with no document (a headless
|
|
629
|
+
// renderer) there is nothing to draw them into.
|
|
630
|
+
if (!selection || typeof document === 'undefined') return null
|
|
631
|
+
// Hovering the plan hides the dimensions rather than unmounting them: drei
|
|
632
|
+
// `Html` unmounts its DOM root synchronously, which React reports as an error
|
|
633
|
+
// when it happens inside a render.
|
|
634
|
+
return (
|
|
635
|
+
<group matrixAutoUpdate={false} ref={root}>
|
|
636
|
+
<RoomDimensionLines3D dimensions={selection.dimensions} hidden={isFloorplanHovered} />
|
|
465
637
|
</group>
|
|
466
638
|
)
|
|
467
639
|
}
|
|
@@ -524,6 +696,7 @@ function MezzanineEdgeArrow({
|
|
|
524
696
|
}
|
|
525
697
|
|
|
526
698
|
export function RoomHandleDragPreview3D() {
|
|
699
|
+
const i18n = usePascalI18n()
|
|
527
700
|
const drag = useRoomHandleDrag((s) => s.drag)
|
|
528
701
|
const unit = useViewer((s) => s.unit)
|
|
529
702
|
const metricNotation = useViewer((s) => s.metricNotation)
|
|
@@ -614,7 +787,9 @@ export function RoomHandleDragPreview3D() {
|
|
|
614
787
|
/>
|
|
615
788
|
<Html center position={[ax, drag.value + 0.35, az]} zIndexRange={[25, 0]}>
|
|
616
789
|
<div className={PILL}>
|
|
617
|
-
<span className="font-medium text-foreground">
|
|
790
|
+
<span className="font-medium text-foreground">
|
|
791
|
+
{i18n._({ id: 'editor.roomHandles.floor', message: 'Floor' })}
|
|
792
|
+
</span>
|
|
618
793
|
<span className="text-muted-foreground">
|
|
619
794
|
{formatMeasurement(
|
|
620
795
|
drag.value - roomFloorBase(useScene.getState().nodes, drag.zoneId),
|
|
@@ -627,6 +802,45 @@ export function RoomHandleDragPreview3D() {
|
|
|
627
802
|
</group>
|
|
628
803
|
)
|
|
629
804
|
}
|
|
805
|
+
const ghosts = drag.ghosts.map((ghost, index) => {
|
|
806
|
+
const length = Math.hypot(ghost.end[0] - ghost.start[0], ghost.end[1] - ghost.start[1])
|
|
807
|
+
if (length < 1e-3) return null
|
|
808
|
+
return (
|
|
809
|
+
<mesh
|
|
810
|
+
key={index}
|
|
811
|
+
layers={EDITOR_LAYER}
|
|
812
|
+
material={materials.fill}
|
|
813
|
+
position={[
|
|
814
|
+
(ghost.start[0] + ghost.end[0]) / 2,
|
|
815
|
+
drag.base + ghost.height / 2,
|
|
816
|
+
(ghost.start[1] + ghost.end[1]) / 2,
|
|
817
|
+
]}
|
|
818
|
+
raycast={noRaycast}
|
|
819
|
+
renderOrder={99}
|
|
820
|
+
rotation={[0, -Math.atan2(ghost.end[1] - ghost.start[1], ghost.end[0] - ghost.start[0]), 0]}
|
|
821
|
+
>
|
|
822
|
+
<boxGeometry args={[length, ghost.height, ghost.thickness]} />
|
|
823
|
+
</mesh>
|
|
824
|
+
)
|
|
825
|
+
})
|
|
826
|
+
if (drag.kind === 'wall-group-push')
|
|
827
|
+
return (
|
|
828
|
+
<group>
|
|
829
|
+
<RoomDimensionLines3D dimensions={drag.dimensions} />
|
|
830
|
+
{ghosts}
|
|
831
|
+
{drag.message && (
|
|
832
|
+
<Html
|
|
833
|
+
center
|
|
834
|
+
position={[drag.anchor[0], drag.height + 0.45, drag.anchor[1]]}
|
|
835
|
+
zIndexRange={[25, 0]}
|
|
836
|
+
>
|
|
837
|
+
<div className={PILL}>
|
|
838
|
+
<span className="font-medium text-red-500">{drag.message}</span>
|
|
839
|
+
</div>
|
|
840
|
+
</Html>
|
|
841
|
+
)}
|
|
842
|
+
</group>
|
|
843
|
+
)
|
|
630
844
|
const at: Point = [
|
|
631
845
|
drag.anchor[0] + drag.outward[0] * drag.distance,
|
|
632
846
|
drag.anchor[1] + drag.outward[1] * drag.distance,
|
|
@@ -636,31 +850,7 @@ export function RoomHandleDragPreview3D() {
|
|
|
636
850
|
return (
|
|
637
851
|
<group>
|
|
638
852
|
<RoomDimensionLines3D dimensions={drag.dimensions} />
|
|
639
|
-
{
|
|
640
|
-
const length = Math.hypot(ghost.end[0] - ghost.start[0], ghost.end[1] - ghost.start[1])
|
|
641
|
-
if (length < 1e-3) return null
|
|
642
|
-
return (
|
|
643
|
-
<mesh
|
|
644
|
-
key={index}
|
|
645
|
-
layers={EDITOR_LAYER}
|
|
646
|
-
material={materials.fill}
|
|
647
|
-
position={[
|
|
648
|
-
(ghost.start[0] + ghost.end[0]) / 2,
|
|
649
|
-
drag.base + ghost.height / 2,
|
|
650
|
-
(ghost.start[1] + ghost.end[1]) / 2,
|
|
651
|
-
]}
|
|
652
|
-
raycast={noRaycast}
|
|
653
|
-
renderOrder={99}
|
|
654
|
-
rotation={[
|
|
655
|
-
0,
|
|
656
|
-
-Math.atan2(ghost.end[1] - ghost.start[1], ghost.end[0] - ghost.start[0]),
|
|
657
|
-
0,
|
|
658
|
-
]}
|
|
659
|
-
>
|
|
660
|
-
<boxGeometry args={[length, ghost.height, ghost.thickness]} />
|
|
661
|
-
</mesh>
|
|
662
|
-
)
|
|
663
|
-
})}
|
|
853
|
+
{ghosts}
|
|
664
854
|
<Html center position={[at[0], drag.height + 0.45, at[1]]} zIndexRange={[25, 0]}>
|
|
665
855
|
<div className={PILL}>
|
|
666
856
|
{drag.message ? (
|
|
@@ -25,6 +25,7 @@ import { describeZoneOutline, type RoomSelectionRecord } from '../../lib/room-se
|
|
|
25
25
|
import useEditor from '../../store/use-editor'
|
|
26
26
|
import useInteractionScope from '../../store/use-interaction-scope'
|
|
27
27
|
import { RoomControls2D, RoomControls3D } from './room-controls'
|
|
28
|
+
import { SelectedWallDimensions3D } from './room-handles'
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* A zone reached as a zone (hovered or selected through its area or pill, not
|
|
@@ -188,6 +189,7 @@ export function RoomHighlight3D() {
|
|
|
188
189
|
return (
|
|
189
190
|
<>
|
|
190
191
|
<RoomControls3D />
|
|
192
|
+
<SelectedWallDimensions3D />
|
|
191
193
|
{room ? <RoomMesh room={room} /> : null}
|
|
192
194
|
</>
|
|
193
195
|
)
|
|
@@ -7,15 +7,18 @@ import {
|
|
|
7
7
|
containsPoint,
|
|
8
8
|
DEFAULT_LEVEL_HEIGHT,
|
|
9
9
|
emitter,
|
|
10
|
+
formatNumber,
|
|
11
|
+
type PascalI18n,
|
|
10
12
|
type Polygon,
|
|
11
13
|
polygonInteriorPoint,
|
|
12
14
|
type Ring,
|
|
13
15
|
sceneRegistry,
|
|
16
|
+
useLocale,
|
|
17
|
+
usePascalI18n,
|
|
14
18
|
useScene,
|
|
15
19
|
type ZoneNode,
|
|
16
20
|
} from '@pascal-app/core'
|
|
17
21
|
import { timeSpan, useViewer } from '@pascal-app/viewer'
|
|
18
|
-
import { Html } from '@react-three/drei'
|
|
19
22
|
import { useFrame, useThree } from '@react-three/fiber'
|
|
20
23
|
import {
|
|
21
24
|
createContext,
|
|
@@ -47,17 +50,14 @@ import { useShallow } from 'zustand/react/shallow'
|
|
|
47
50
|
import { useRoomRecords } from '../../hooks/use-selected-room'
|
|
48
51
|
import { getAreaUnitLabel, type LinearUnit, squareMetersToAreaUnit } from '../../lib/measurements'
|
|
49
52
|
import { roomFloorElevation } from '../../lib/room-handle-drag'
|
|
53
|
+
import { displayRoomName } from '../../lib/room-name-messages'
|
|
50
54
|
import type { RoomSelectionRecord } from '../../lib/room-selection'
|
|
51
|
-
import {
|
|
52
|
-
clickZoneArea,
|
|
53
|
-
hoverZoneArea,
|
|
54
|
-
leaveZoneArea,
|
|
55
|
-
zoneKindLabel,
|
|
56
|
-
} from '../../lib/room-zone-routing'
|
|
55
|
+
import { clickZoneArea, hoverZoneArea, leaveZoneArea } from '../../lib/room-zone-routing'
|
|
57
56
|
import { selectionModifiersFromEvent } from '../../lib/selection-routing'
|
|
58
57
|
import useEditor from '../../store/use-editor'
|
|
59
58
|
import useInteractionScope from '../../store/use-interaction-scope'
|
|
60
59
|
import { isViewVisible, VIEW_2D, VIEW_3D } from '../../store/view-layout'
|
|
60
|
+
import { Html } from './localized-html'
|
|
61
61
|
|
|
62
62
|
const CONTEXT_TYPES = new Set(['site', 'building', 'level'])
|
|
63
63
|
|
|
@@ -92,8 +92,12 @@ export function roomLabelsVisible(state: RoomLabelVisibilityState): boolean {
|
|
|
92
92
|
)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export function formatRoomArea(squareMeters: number, unit: LinearUnit): string {
|
|
96
|
-
return `${squareMetersToAreaUnit(squareMeters, unit)
|
|
95
|
+
export function formatRoomArea(squareMeters: number, unit: LinearUnit, locale?: string): string {
|
|
96
|
+
return `${formatNumber(squareMetersToAreaUnit(squareMeters, unit), {
|
|
97
|
+
min: 1,
|
|
98
|
+
max: 1,
|
|
99
|
+
locale,
|
|
100
|
+
})} ${getAreaUnitLabel(unit)}`
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
function useRoomLabelsVisible() {
|
|
@@ -1169,11 +1173,12 @@ export function RoomPillChip({
|
|
|
1169
1173
|
onLeave: () => void
|
|
1170
1174
|
}) {
|
|
1171
1175
|
const unit = useViewer((s) => s.unit)
|
|
1172
|
-
const
|
|
1176
|
+
const locale = useLocale()
|
|
1177
|
+
const areaLabel = formatRoomArea(areaM2, unit, locale)
|
|
1173
1178
|
// biome-ignore lint/correctness/useExhaustiveDependencies: A dot's border box does not resize when its hidden text changes.
|
|
1174
1179
|
useLayoutEffect(() => {
|
|
1175
1180
|
if (elements instanceof PillElements) elements.measure(zoneId)
|
|
1176
|
-
}, [areaM2, elements, name, unit, zoneId])
|
|
1181
|
+
}, [areaM2, elements, locale, name, unit, zoneId])
|
|
1177
1182
|
const register = useCallback(
|
|
1178
1183
|
(element: HTMLElement | null) => {
|
|
1179
1184
|
if (element) elements.set(zoneId, element)
|
|
@@ -1227,6 +1232,7 @@ export function RoomPillDetail({
|
|
|
1227
1232
|
areaM2: number
|
|
1228
1233
|
}) {
|
|
1229
1234
|
const unit = useViewer((s) => s.unit)
|
|
1235
|
+
const locale = useLocale()
|
|
1230
1236
|
return (
|
|
1231
1237
|
<div
|
|
1232
1238
|
aria-hidden
|
|
@@ -1234,7 +1240,7 @@ export function RoomPillDetail({
|
|
|
1234
1240
|
data-room-label-detail={zoneId}
|
|
1235
1241
|
data-room-label-view={view}
|
|
1236
1242
|
>
|
|
1237
|
-
<LabelParts areaLabel={formatRoomArea(areaM2, unit)} color={color} full name={name} />
|
|
1243
|
+
<LabelParts areaLabel={formatRoomArea(areaM2, unit, locale)} color={color} full name={name} />
|
|
1238
1244
|
</div>
|
|
1239
1245
|
)
|
|
1240
1246
|
}
|
|
@@ -1244,7 +1250,13 @@ function useLabelZone(zoneId: string) {
|
|
|
1244
1250
|
return zone && zone.visible !== false ? zone : null
|
|
1245
1251
|
}
|
|
1246
1252
|
|
|
1247
|
-
const labelName = (zone: ZoneNode
|
|
1253
|
+
const labelName = (zone: ZoneNode, i18n: PascalI18n) => {
|
|
1254
|
+
const name = zone.name?.trim()
|
|
1255
|
+
if (name) return displayRoomName(name, i18n)
|
|
1256
|
+
return zone.spaceRole === 'room'
|
|
1257
|
+
? i18n._({ id: 'editor.roomLabel.room', message: 'Room' })
|
|
1258
|
+
: i18n._({ id: 'editor.roomLabel.zone', message: 'Zone' })
|
|
1259
|
+
}
|
|
1248
1260
|
|
|
1249
1261
|
/**
|
|
1250
1262
|
* One room's pill in the editor. Hover and click take the same rule as the
|
|
@@ -1260,6 +1272,7 @@ function RoomPill({
|
|
|
1260
1272
|
view: '2d' | '3d'
|
|
1261
1273
|
elements: Map<string, HTMLElement>
|
|
1262
1274
|
}) {
|
|
1275
|
+
const i18n = usePascalI18n()
|
|
1263
1276
|
const zone = useLabelZone(entry.zoneId)
|
|
1264
1277
|
// A pill that disappears under the cursor (its click selected something)
|
|
1265
1278
|
// fires no leave: end the hover it set.
|
|
@@ -1270,7 +1283,7 @@ function RoomPill({
|
|
|
1270
1283
|
areaM2={entry.area}
|
|
1271
1284
|
color={zone.color}
|
|
1272
1285
|
elements={elements}
|
|
1273
|
-
name={labelName(zone)}
|
|
1286
|
+
name={labelName(zone, i18n)}
|
|
1274
1287
|
onClick={(event) => clickZoneArea(entry.zoneId, selectionModifiersFromEvent(event))}
|
|
1275
1288
|
onHover={(event) => hoverZoneArea(entry.zoneId, selectionModifiersFromEvent(event))}
|
|
1276
1289
|
onLeave={() => leaveZoneArea(entry.zoneId)}
|
|
@@ -1281,13 +1294,14 @@ function RoomPill({
|
|
|
1281
1294
|
}
|
|
1282
1295
|
|
|
1283
1296
|
function RoomDetail({ entry, view }: { entry: LabelEntry; view: '2d' | '3d' }) {
|
|
1297
|
+
const i18n = usePascalI18n()
|
|
1284
1298
|
const zone = useLabelZone(entry.zoneId)
|
|
1285
1299
|
if (!zone) return null
|
|
1286
1300
|
return (
|
|
1287
1301
|
<RoomPillDetail
|
|
1288
1302
|
areaM2={entry.area}
|
|
1289
1303
|
color={zone.color}
|
|
1290
|
-
name={labelName(zone)}
|
|
1304
|
+
name={labelName(zone, i18n)}
|
|
1291
1305
|
view={view}
|
|
1292
1306
|
zoneId={entry.zoneId}
|
|
1293
1307
|
/>
|