@pascal-app/editor 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +11 -11
- 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 -1981
- package/src/components/editor/floating-action-menu.tsx +1 -1
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floor-region-controls.tsx +6 -2
- 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 +26 -22
- package/src/components/editor/floorplan-wall-typing-keys.ts +1 -1
- 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 +1 -1
- 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/handles/use-handle-drag.ts +1 -2
- package/src/components/editor/index.tsx +24 -14
- package/src/components/editor/inspector-extension-actions.tsx +1 -1
- package/src/components/editor/node-arrow-handles.tsx +1 -1
- 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/room-controls.tsx +7 -4
- package/src/components/editor/room-handles-2d.tsx +2 -3
- package/src/components/editor/room-handles.tsx +1 -2
- 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 +40 -1671
- 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 +1 -1
- 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 +1 -1
- package/src/components/editor/wall-move-side-handles.tsx +1 -1
- package/src/components/editor/wall-pull-grip.tsx +2 -2
- package/src/components/editor-2d/floorplan-group-move.tsx +2 -3
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1 -1
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +1 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +1 -2
- 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-placement-preview-layer.tsx +1 -2
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +8 -10
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +25 -33
- package/src/components/systems/roof/roof-edit-system.tsx +4 -3
- package/src/components/tools/distribution/distribution-run-tool.tsx +1 -1
- package/src/components/tools/item/placement-history.test.tsx +1 -1
- package/src/components/tools/item/use-placement-coordinator.tsx +2 -3
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +6 -2
- package/src/components/tools/registry/move-registry-node-tool.tsx +1 -2
- 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 +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/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/terrain-sculpt-panel.tsx +1 -1
- 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 +1 -1
- package/src/components/ui/helpers/helper-manager.tsx +1 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/node-icon-image.test.tsx +46 -0
- package/src/components/ui/node-icon-image.tsx +33 -1
- package/src/components/ui/panels/collections/collections-popover.tsx +2 -2
- package/src/components/ui/panels/floor-foundation-panel.tsx +2 -2
- package/src/components/ui/panels/floor-opening-panel.tsx +4 -4
- package/src/components/ui/panels/node-display.ts +1 -1
- package/src/components/ui/panels/panel-manager.tsx +1 -1
- package/src/components/ui/panels/panel-wrapper.tsx +1 -1
- package/src/components/ui/panels/parametric-inspector.tsx +1 -1
- package/src/components/ui/panels/room-construction-rows.tsx +6 -6
- package/src/components/ui/panels/room-name-options.ts +1 -5
- package/src/components/ui/panels/room-panel.tsx +6 -8
- 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.tsx +1 -1
- 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 +1 -1
- 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/index.tsx +2 -2
- 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/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/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 +1 -1
- 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 +180 -182
- package/src/i18n/locales/es/messages.po +180 -182
- package/src/i18n/locales/fr/messages.po +180 -182
- package/src/i18n/locales/ja/messages.po +180 -182
- package/src/i18n/locales/zh-CN/messages.po +180 -182
- package/src/i18n/locales.test.ts +1 -1
- package/src/index.tsx +109 -131
- 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/editor-level-display.ts +1 -1
- package/src/lib/floor-footprints.test.ts +2 -2
- package/src/lib/floor-opening-draft.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/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/glb-export.ts +1 -1
- package/src/lib/material-paint.ts +1 -1
- package/src/lib/measurements.test.ts +2 -1
- package/src/lib/mezzanine-selection.test.ts +1 -1
- package/src/lib/paint-region-mode.ts +1 -1
- package/src/lib/point-ask/session.ts +1 -2
- package/src/lib/roof-duplication.test.ts +100 -0
- package/src/lib/roof-duplication.ts +30 -5
- package/src/lib/room-handle-drag.ts +2 -12
- 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-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/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/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/store/use-editor.tsx +17 -26
- package/src/store/use-floorplan-annotation-visibility.ts +5 -5
- 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/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/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/measurements.ts +0 -8
- 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 -327
- package/src/lib/scene-bounds.ts +0 -233
- package/src/lib/typing-target.ts +0 -9
- package/src/lib/viewer-selection.ts +0 -595
- 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
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
|
|
4
|
-
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'
|
|
5
|
-
import type * as React from 'react'
|
|
6
|
-
|
|
7
|
-
import { cn } from '../../../lib/utils'
|
|
8
|
-
|
|
9
|
-
function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
10
|
-
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function DropdownMenuPortal({
|
|
14
|
-
...props
|
|
15
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
16
|
-
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function DropdownMenuTrigger({
|
|
20
|
-
...props
|
|
21
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
22
|
-
return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function DropdownMenuContent({
|
|
26
|
-
className,
|
|
27
|
-
sideOffset = 4,
|
|
28
|
-
...props
|
|
29
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
30
|
-
return (
|
|
31
|
-
<DropdownMenuPrimitive.Portal>
|
|
32
|
-
<DropdownMenuPrimitive.Content
|
|
33
|
-
className={cn(
|
|
34
|
-
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
|
|
35
|
-
className,
|
|
36
|
-
)}
|
|
37
|
-
data-slot="dropdown-menu-content"
|
|
38
|
-
sideOffset={sideOffset}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
</DropdownMenuPrimitive.Portal>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
46
|
-
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function DropdownMenuItem({
|
|
50
|
-
className,
|
|
51
|
-
inset,
|
|
52
|
-
variant = 'default',
|
|
53
|
-
...props
|
|
54
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
55
|
-
inset?: boolean
|
|
56
|
-
variant?: 'default' | 'destructive'
|
|
57
|
-
}) {
|
|
58
|
-
return (
|
|
59
|
-
<DropdownMenuPrimitive.Item
|
|
60
|
-
className={cn(
|
|
61
|
-
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-8 data-[variant=destructive]:text-destructive data-disabled:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 data-[variant=destructive]:*:[svg]:text-destructive!",
|
|
62
|
-
className,
|
|
63
|
-
)}
|
|
64
|
-
data-inset={inset}
|
|
65
|
-
data-slot="dropdown-menu-item"
|
|
66
|
-
data-variant={variant}
|
|
67
|
-
{...props}
|
|
68
|
-
/>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function DropdownMenuCheckboxItem({
|
|
73
|
-
className,
|
|
74
|
-
children,
|
|
75
|
-
checked,
|
|
76
|
-
...props
|
|
77
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
78
|
-
return (
|
|
79
|
-
<DropdownMenuPrimitive.CheckboxItem
|
|
80
|
-
checked={checked}
|
|
81
|
-
className={cn(
|
|
82
|
-
"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
83
|
-
className,
|
|
84
|
-
)}
|
|
85
|
-
data-slot="dropdown-menu-checkbox-item"
|
|
86
|
-
{...props}
|
|
87
|
-
>
|
|
88
|
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
89
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
90
|
-
<CheckIcon className="size-4" />
|
|
91
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
92
|
-
</span>
|
|
93
|
-
{children}
|
|
94
|
-
</DropdownMenuPrimitive.CheckboxItem>
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function DropdownMenuRadioGroup({
|
|
99
|
-
...props
|
|
100
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
101
|
-
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function DropdownMenuRadioItem({
|
|
105
|
-
className,
|
|
106
|
-
children,
|
|
107
|
-
...props
|
|
108
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
109
|
-
return (
|
|
110
|
-
<DropdownMenuPrimitive.RadioItem
|
|
111
|
-
className={cn(
|
|
112
|
-
"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
113
|
-
className,
|
|
114
|
-
)}
|
|
115
|
-
data-slot="dropdown-menu-radio-item"
|
|
116
|
-
{...props}
|
|
117
|
-
>
|
|
118
|
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
119
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
120
|
-
<CircleIcon className="size-2 fill-current" />
|
|
121
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
122
|
-
</span>
|
|
123
|
-
{children}
|
|
124
|
-
</DropdownMenuPrimitive.RadioItem>
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function DropdownMenuLabel({
|
|
129
|
-
className,
|
|
130
|
-
inset,
|
|
131
|
-
...props
|
|
132
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
133
|
-
inset?: boolean
|
|
134
|
-
}) {
|
|
135
|
-
return (
|
|
136
|
-
<DropdownMenuPrimitive.Label
|
|
137
|
-
className={cn('px-2 py-1.5 font-barlow font-medium text-sm data-inset:pl-8', className)}
|
|
138
|
-
data-inset={inset}
|
|
139
|
-
data-slot="dropdown-menu-label"
|
|
140
|
-
{...props}
|
|
141
|
-
/>
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function DropdownMenuSeparator({
|
|
146
|
-
className,
|
|
147
|
-
...props
|
|
148
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
149
|
-
return (
|
|
150
|
-
<DropdownMenuPrimitive.Separator
|
|
151
|
-
className={cn('-mx-1 my-1 h-px bg-border', className)}
|
|
152
|
-
data-slot="dropdown-menu-separator"
|
|
153
|
-
{...props}
|
|
154
|
-
/>
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
159
|
-
return (
|
|
160
|
-
<span
|
|
161
|
-
className={cn('ml-auto text-muted-foreground text-xs tracking-widest', className)}
|
|
162
|
-
data-slot="dropdown-menu-shortcut"
|
|
163
|
-
{...props}
|
|
164
|
-
/>
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
169
|
-
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function DropdownMenuSubTrigger({
|
|
173
|
-
className,
|
|
174
|
-
inset,
|
|
175
|
-
children,
|
|
176
|
-
...props
|
|
177
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
178
|
-
inset?: boolean
|
|
179
|
-
}) {
|
|
180
|
-
return (
|
|
181
|
-
<DropdownMenuPrimitive.SubTrigger
|
|
182
|
-
className={cn(
|
|
183
|
-
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-inset:pl-8 data-[state=open]:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
184
|
-
className,
|
|
185
|
-
)}
|
|
186
|
-
data-inset={inset}
|
|
187
|
-
data-slot="dropdown-menu-sub-trigger"
|
|
188
|
-
{...props}
|
|
189
|
-
>
|
|
190
|
-
{children}
|
|
191
|
-
<ChevronRightIcon className="ml-auto size-4" />
|
|
192
|
-
</DropdownMenuPrimitive.SubTrigger>
|
|
193
|
-
)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function DropdownMenuSubContent({
|
|
197
|
-
className,
|
|
198
|
-
...props
|
|
199
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
200
|
-
// Portalled so the side-opening submenu escapes the parent content's
|
|
201
|
-
// `overflow-x-hidden` clip (otherwise it renders but is invisible).
|
|
202
|
-
return (
|
|
203
|
-
<DropdownMenuPrimitive.Portal>
|
|
204
|
-
<DropdownMenuPrimitive.SubContent
|
|
205
|
-
className={cn(
|
|
206
|
-
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in',
|
|
207
|
-
className,
|
|
208
|
-
)}
|
|
209
|
-
data-slot="dropdown-menu-sub-content"
|
|
210
|
-
{...props}
|
|
211
|
-
/>
|
|
212
|
-
</DropdownMenuPrimitive.Portal>
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export {
|
|
217
|
-
DropdownMenu,
|
|
218
|
-
DropdownMenuPortal,
|
|
219
|
-
DropdownMenuTrigger,
|
|
220
|
-
DropdownMenuContent,
|
|
221
|
-
DropdownMenuGroup,
|
|
222
|
-
DropdownMenuLabel,
|
|
223
|
-
DropdownMenuItem,
|
|
224
|
-
DropdownMenuCheckboxItem,
|
|
225
|
-
DropdownMenuRadioGroup,
|
|
226
|
-
DropdownMenuRadioItem,
|
|
227
|
-
DropdownMenuSeparator,
|
|
228
|
-
DropdownMenuShortcut,
|
|
229
|
-
DropdownMenuSub,
|
|
230
|
-
DropdownMenuSubTrigger,
|
|
231
|
-
DropdownMenuSubContent,
|
|
232
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
|
4
|
-
import type * as React from 'react'
|
|
5
|
-
|
|
6
|
-
import { cn } from '../../../lib/utils'
|
|
7
|
-
|
|
8
|
-
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
|
9
|
-
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
|
13
|
-
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function PopoverContent({
|
|
17
|
-
className,
|
|
18
|
-
align = 'center',
|
|
19
|
-
sideOffset = 4,
|
|
20
|
-
...props
|
|
21
|
-
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
|
22
|
-
return (
|
|
23
|
-
<PopoverPrimitive.Portal>
|
|
24
|
-
<PopoverPrimitive.Content
|
|
25
|
-
align={align}
|
|
26
|
-
className={cn(
|
|
27
|
-
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
|
28
|
-
className,
|
|
29
|
-
)}
|
|
30
|
-
data-slot="popover-content"
|
|
31
|
-
sideOffset={sideOffset}
|
|
32
|
-
{...props}
|
|
33
|
-
/>
|
|
34
|
-
</PopoverPrimitive.Portal>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
|
39
|
-
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as SwitchPrimitives from '@radix-ui/react-switch'
|
|
4
|
-
import * as React from 'react'
|
|
5
|
-
|
|
6
|
-
import { cn } from './../../../lib/utils'
|
|
7
|
-
|
|
8
|
-
const Switch = React.forwardRef<
|
|
9
|
-
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
10
|
-
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
11
|
-
>(({ className, ...props }, ref) => (
|
|
12
|
-
<SwitchPrimitives.Root
|
|
13
|
-
className={cn(
|
|
14
|
-
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
|
|
15
|
-
className,
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
ref={ref}
|
|
19
|
-
>
|
|
20
|
-
<SwitchPrimitives.Thumb
|
|
21
|
-
className={cn(
|
|
22
|
-
'pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',
|
|
23
|
-
)}
|
|
24
|
-
/>
|
|
25
|
-
</SwitchPrimitives.Root>
|
|
26
|
-
))
|
|
27
|
-
Switch.displayName = SwitchPrimitives.Root.displayName
|
|
28
|
-
|
|
29
|
-
export { Switch }
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
|
4
|
-
import type * as React from 'react'
|
|
5
|
-
|
|
6
|
-
import { cn } from '../../../lib/utils'
|
|
7
|
-
|
|
8
|
-
function TooltipProvider({
|
|
9
|
-
delayDuration = 0,
|
|
10
|
-
...props
|
|
11
|
-
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
12
|
-
return (
|
|
13
|
-
<TooltipPrimitive.Provider
|
|
14
|
-
data-slot="tooltip-provider"
|
|
15
|
-
delayDuration={delayDuration}
|
|
16
|
-
{...props}
|
|
17
|
-
/>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
22
|
-
return (
|
|
23
|
-
<TooltipProvider>
|
|
24
|
-
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
-
</TooltipProvider>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
30
|
-
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function TooltipContent({
|
|
34
|
-
className,
|
|
35
|
-
sideOffset = 0,
|
|
36
|
-
children,
|
|
37
|
-
...props
|
|
38
|
-
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
39
|
-
return (
|
|
40
|
-
<TooltipPrimitive.Portal>
|
|
41
|
-
<TooltipPrimitive.Content
|
|
42
|
-
className={cn(
|
|
43
|
-
'fade-in-0 zoom-in-95 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in text-balance rounded-md bg-foreground px-3 py-1.5 font-barlow text-background text-xs data-[state=closed]:animate-out',
|
|
44
|
-
className,
|
|
45
|
-
)}
|
|
46
|
-
data-slot="tooltip-content"
|
|
47
|
-
sideOffset={sideOffset}
|
|
48
|
-
{...props}
|
|
49
|
-
>
|
|
50
|
-
{children}
|
|
51
|
-
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
|
52
|
-
</TooltipPrimitive.Content>
|
|
53
|
-
</TooltipPrimitive.Portal>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
-
import { cn } from '../../lib/utils'
|
|
5
|
-
import { Button } from './primitives/button'
|
|
6
|
-
|
|
7
|
-
const LOADERS = [
|
|
8
|
-
'pascal-loader-1',
|
|
9
|
-
'pascal-loader-2',
|
|
10
|
-
'pascal-loader-3',
|
|
11
|
-
'pascal-loader-4',
|
|
12
|
-
'pascal-loader-5',
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
interface SceneLoaderProps {
|
|
16
|
-
className?: string
|
|
17
|
-
fullScreen?: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function SceneLoader({ className, fullScreen = false }: SceneLoaderProps) {
|
|
21
|
-
const [loaderClass, setLoaderClass] = useState(LOADERS[0]!)
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
// Pick a random loader on mount
|
|
25
|
-
setLoaderClass(LOADERS[Math.floor(Math.random() * LOADERS.length)] ?? LOADERS[0]!)
|
|
26
|
-
}, [])
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div
|
|
30
|
-
className={cn(
|
|
31
|
-
'z-100 flex items-center justify-center bg-background/80 backdrop-blur-md transition-opacity duration-300',
|
|
32
|
-
fullScreen ? 'fixed inset-0' : 'absolute inset-0',
|
|
33
|
-
className,
|
|
34
|
-
)}
|
|
35
|
-
>
|
|
36
|
-
<div className={cn(loaderClass, 'text-foreground opacity-80')} />
|
|
37
|
-
</div>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface SceneLoadFailedProps {
|
|
42
|
-
className?: string
|
|
43
|
-
onRetry: () => void
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Replaces the loader when the host could not deliver the scene. Rendered
|
|
48
|
-
* INSTEAD of falling back to an empty default scene: a session that shows
|
|
49
|
-
* scaffold nodes after a failed load autosaves that scaffold over the real
|
|
50
|
-
* project (prod scene-wipe class, 2026-09-02).
|
|
51
|
-
*/
|
|
52
|
-
export function SceneLoadFailed({ className, onRetry }: SceneLoadFailedProps) {
|
|
53
|
-
return (
|
|
54
|
-
<div
|
|
55
|
-
className={cn(
|
|
56
|
-
'z-100 flex flex-col items-center justify-center gap-4 bg-background/90 px-6 text-center backdrop-blur-md',
|
|
57
|
-
'absolute inset-0',
|
|
58
|
-
className,
|
|
59
|
-
)}
|
|
60
|
-
role="alert"
|
|
61
|
-
>
|
|
62
|
-
<div className="flex flex-col gap-1">
|
|
63
|
-
<p className="font-medium text-foreground text-sm">This project couldn't be loaded</p>
|
|
64
|
-
<p className="text-muted-foreground text-sm">
|
|
65
|
-
Nothing was changed. Check your connection and try again.
|
|
66
|
-
</p>
|
|
67
|
-
</div>
|
|
68
|
-
<Button className="rounded-full" onClick={onRetry} size="sm" type="button">
|
|
69
|
-
Try again
|
|
70
|
-
</Button>
|
|
71
|
-
</div>
|
|
72
|
-
)
|
|
73
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { usePascalI18n } from '@pascal-app/core'
|
|
4
|
-
import type React from 'react'
|
|
5
|
-
import { cn } from '../../lib/utils'
|
|
6
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/primitives/tooltip'
|
|
7
|
-
import { SKY_COMPASS_BOTTOM, useSkyPanel } from './sky-control'
|
|
8
|
-
|
|
9
|
-
export type FloorplanCompassButtonProps = {
|
|
10
|
-
northRotationDeg: number
|
|
11
|
-
onAlignNorth: () => void
|
|
12
|
-
needleRef?: React.RefObject<SVGSVGElement | null>
|
|
13
|
-
/** Horizontal anchor; defaults to the bottom-left corner. */
|
|
14
|
-
style?: React.CSSProperties
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function FloorplanCompassButton({
|
|
18
|
-
northRotationDeg,
|
|
19
|
-
onAlignNorth,
|
|
20
|
-
needleRef,
|
|
21
|
-
style,
|
|
22
|
-
}: FloorplanCompassButtonProps) {
|
|
23
|
-
const i18n = usePascalI18n()
|
|
24
|
-
// Beside the sky chip (not when moved to the plan's right corner), centre on the docks' row.
|
|
25
|
-
const besideSky = useSkyPanel((s) => s.hosts > 0) && style?.right === undefined
|
|
26
|
-
const label = i18n._({
|
|
27
|
-
id: 'viewer.floorplan.alignNorth',
|
|
28
|
-
message: 'Align view to north',
|
|
29
|
-
})
|
|
30
|
-
return (
|
|
31
|
-
<Tooltip>
|
|
32
|
-
<TooltipTrigger asChild>
|
|
33
|
-
<button
|
|
34
|
-
aria-label={label}
|
|
35
|
-
className={cn(
|
|
36
|
-
'group pointer-events-auto absolute bottom-3 z-30 flex h-8 w-8 items-center justify-center rounded-full border border-black/10 bg-white/85 shadow-sm backdrop-blur-md transition hover:bg-white hover:shadow-md dark:border-white/10 dark:bg-neutral-900/85 dark:hover:bg-neutral-900',
|
|
37
|
-
!style && 'left-3',
|
|
38
|
-
)}
|
|
39
|
-
style={besideSky ? { bottom: SKY_COMPASS_BOTTOM, ...style } : style}
|
|
40
|
-
onClick={(event) => {
|
|
41
|
-
event.preventDefault()
|
|
42
|
-
event.stopPropagation()
|
|
43
|
-
onAlignNorth()
|
|
44
|
-
}}
|
|
45
|
-
onPointerDown={(event) => {
|
|
46
|
-
event.stopPropagation()
|
|
47
|
-
}}
|
|
48
|
-
type="button"
|
|
49
|
-
>
|
|
50
|
-
<span className="relative flex h-6 w-6 items-center justify-center rounded-full bg-[#b8b8b8] shadow-inner dark:bg-neutral-700">
|
|
51
|
-
<svg
|
|
52
|
-
aria-hidden="true"
|
|
53
|
-
className="h-6 w-6"
|
|
54
|
-
ref={needleRef}
|
|
55
|
-
style={{ transform: `rotate(${northRotationDeg}deg)` }}
|
|
56
|
-
viewBox="0 0 48 48"
|
|
57
|
-
>
|
|
58
|
-
<path d="M24 4.5 31.5 25 24 21.5 16.5 25Z" fill="#f15b5b" />
|
|
59
|
-
<path d="M24 43.5 16.5 23 24 26.5 31.5 23Z" fill="#ffffff" />
|
|
60
|
-
</svg>
|
|
61
|
-
</span>
|
|
62
|
-
</button>
|
|
63
|
-
</TooltipTrigger>
|
|
64
|
-
<TooltipContent side="right">{label}</TooltipContent>
|
|
65
|
-
</Tooltip>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import type { FloorplanGeometry } from '@pascal-app/core'
|
|
3
|
-
import {
|
|
4
|
-
clientToFloorplanPoint,
|
|
5
|
-
getFloorplanBounds,
|
|
6
|
-
padFloorplanBounds,
|
|
7
|
-
panFloorplanViewBox,
|
|
8
|
-
scaleFloorplanViewBox,
|
|
9
|
-
scaleFloorplanViewBoxBetweenClients,
|
|
10
|
-
} from './floorplan-preview-geometry'
|
|
11
|
-
|
|
12
|
-
describe('floorplan preview bounds', () => {
|
|
13
|
-
test('composes nested translation and rotation', () => {
|
|
14
|
-
const geometry: FloorplanGeometry = {
|
|
15
|
-
kind: 'group',
|
|
16
|
-
transform: { translate: [10, 5], rotate: Math.PI / 2 },
|
|
17
|
-
children: [
|
|
18
|
-
{
|
|
19
|
-
kind: 'rect',
|
|
20
|
-
x: 0,
|
|
21
|
-
y: 0,
|
|
22
|
-
width: 4,
|
|
23
|
-
height: 2,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
expect(getFloorplanBounds([geometry])).toEqual({
|
|
29
|
-
minX: 8,
|
|
30
|
-
minY: 5,
|
|
31
|
-
maxX: 10,
|
|
32
|
-
maxY: 9,
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('includes image rotation and dimension baselines', () => {
|
|
37
|
-
const geometries: FloorplanGeometry[] = [
|
|
38
|
-
{
|
|
39
|
-
kind: 'image',
|
|
40
|
-
url: '/symbol.png',
|
|
41
|
-
center: [2, 3],
|
|
42
|
-
width: 4,
|
|
43
|
-
height: 2,
|
|
44
|
-
rotation: Math.PI / 2,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
kind: 'dimension',
|
|
48
|
-
start: [-3, -2],
|
|
49
|
-
end: [3, -2],
|
|
50
|
-
dimensionStart: [-4, -1],
|
|
51
|
-
dimensionEnd: [4, -1],
|
|
52
|
-
offsetNormal: [0, -1],
|
|
53
|
-
offsetDistance: 1,
|
|
54
|
-
extensionOvershoot: 0.2,
|
|
55
|
-
text: '8 m',
|
|
56
|
-
},
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
expect(getFloorplanBounds(geometries)).toEqual({
|
|
60
|
-
minX: -4,
|
|
61
|
-
minY: -2,
|
|
62
|
-
maxX: 4,
|
|
63
|
-
maxY: 5,
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('pads narrow plans by a usable minimum', () => {
|
|
68
|
-
expect(padFloorplanBounds({ minX: 0, minY: 0, maxX: 0, maxY: 0 })).toEqual({
|
|
69
|
-
minX: -0.75,
|
|
70
|
-
minY: -0.75,
|
|
71
|
-
maxX: 0.75,
|
|
72
|
-
maxY: 0.75,
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('maps clients through letterboxed SVG content', () => {
|
|
77
|
-
const viewBox = { x: 0, y: 0, width: 10, height: 10 }
|
|
78
|
-
const viewport = { left: 0, top: 0, width: 1000, height: 500 }
|
|
79
|
-
|
|
80
|
-
expect(clientToFloorplanPoint(viewBox, viewport, 250, 0)).toEqual([0, 0])
|
|
81
|
-
expect(clientToFloorplanPoint(viewBox, viewport, 750, 500)).toEqual([10, 10])
|
|
82
|
-
expect(panFloorplanViewBox(viewBox, viewport, [500, 250], [550, 250])).toEqual({
|
|
83
|
-
x: -1,
|
|
84
|
-
y: 0,
|
|
85
|
-
width: 10,
|
|
86
|
-
height: 10,
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
test('keeps the plan point beneath a moving pinch midpoint', () => {
|
|
91
|
-
const viewBox = { x: 0, y: 0, width: 10, height: 10 }
|
|
92
|
-
const viewport = { left: 0, top: 0, width: 1000, height: 500 }
|
|
93
|
-
const next = scaleFloorplanViewBoxBetweenClients(viewBox, 0.5, viewport, [500, 250], [600, 250])
|
|
94
|
-
|
|
95
|
-
expect(next).toEqual({ x: 1.5, y: 2.5, width: 5, height: 5 })
|
|
96
|
-
expect(clientToFloorplanPoint(next, viewport, 600, 250)).toEqual([5, 5])
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('clamps zoom without changing the view box aspect ratio', () => {
|
|
100
|
-
expect(scaleFloorplanViewBox({ x: 0, y: 0, width: 100, height: 1 }, 0.01)).toEqual({
|
|
101
|
-
x: 37.5,
|
|
102
|
-
y: 0.375,
|
|
103
|
-
width: 25,
|
|
104
|
-
height: 0.25,
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
})
|