@pascal-app/editor 1.0.3 → 1.0.5
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/README.md +106 -0
- package/package.json +42 -38
- package/src/components/editor/__bench__/room-label-placement.bench.ts +108 -0
- package/src/components/editor/action-menu-button.tsx +83 -0
- package/src/components/editor/bake-thumbnail.tsx +307 -5
- package/src/components/editor/capture-level-picker.tsx +72 -0
- package/src/components/editor/construction-reveal-audio.test.tsx +150 -0
- package/src/components/editor/construction-reveal-audio.tsx +40 -0
- package/src/components/editor/custom-camera-controls.tsx +275 -57
- package/src/components/editor/delete-confirmation-dialog.tsx +297 -7
- package/src/components/editor/duplicate-node.ts +244 -0
- package/src/components/editor/editor-layout-mobile.tsx +37 -26
- package/src/components/editor/editor-layout-v2.tsx +132 -59
- package/src/components/editor/export-manager.tsx +47 -26
- package/src/components/editor/first-person/build-collider-world.test.ts +320 -0
- package/src/components/editor/first-person/build-collider-world.ts +28 -7
- package/src/components/editor/first-person/ground-holes.test.ts +128 -0
- package/src/components/editor/first-person/ground-holes.ts +130 -0
- package/src/components/editor/first-person/mechanism-targets.test.ts +162 -0
- package/src/components/editor/first-person/mechanism-targets.ts +88 -0
- package/src/components/editor/first-person-controls.tsx +220 -9
- package/src/components/editor/floating-action-menu.tsx +63 -207
- package/src/components/editor/floor-aware-camera-controls.test.ts +466 -0
- package/src/components/editor/floor-aware-camera-controls.ts +324 -0
- package/src/components/editor/floor-openings-overlay.tsx +243 -0
- package/src/components/editor/floor-region-controls.tsx +846 -0
- package/src/components/editor/floor-region-webgpu-materials.test.ts +12 -0
- package/src/components/editor/floor-surface.test.ts +165 -0
- package/src/components/editor/floor-surface.ts +182 -0
- package/src/components/editor/floorplan-background-selection.test.ts +11 -2
- package/src/components/editor/floorplan-background-selection.ts +1 -3
- package/src/components/editor/floorplan-mode-coordinator.tsx +2 -2
- package/src/components/editor/floorplan-panel.tsx +414 -363
- package/src/components/editor/follow-pascal.test.tsx +912 -0
- package/src/components/editor/follow-pascal.tsx +354 -0
- package/src/components/editor/footprint-height-handle.tsx +204 -0
- package/src/components/editor/group-actions.ts +56 -2
- package/src/components/editor/group-move-3d.ts +2 -0
- package/src/components/editor/group-rotate-handle.tsx +2 -0
- package/src/components/editor/group-transform-shared.test.ts +460 -0
- package/src/components/editor/handles/handle-hit-priority.test.tsx +63 -0
- package/src/components/editor/handles/handle-hit-priority.tsx +37 -0
- package/src/components/editor/handles/swallow-next-click.test.ts +28 -0
- package/src/components/editor/handles/use-handle-drag.ts +269 -197
- package/src/components/editor/index.tsx +409 -197
- package/src/components/editor/join-walls-pill.tsx +44 -0
- package/src/components/editor/node-action-menu.tsx +68 -70
- package/src/components/editor/node-arrow-handles.tsx +25 -6
- package/src/components/editor/open-wall-ends-3d-layer.tsx +273 -0
- package/src/components/editor/open-wall-ends-hint.tsx +89 -0
- package/src/components/editor/quick-measurement-hud.tsx +3 -2
- package/src/components/editor/registry-action-contributions.test.tsx +63 -0
- package/src/components/editor/registry-action-contributions.tsx +80 -1
- package/src/components/editor/riser-diagram-panel.tsx +14 -7
- package/src/components/editor/room-controls.tsx +847 -0
- package/src/components/editor/room-floor-highlight.tsx +128 -0
- package/src/components/editor/room-handles-2d.tsx +354 -0
- package/src/components/editor/room-handles.tsx +675 -0
- package/src/components/editor/room-highlight.tsx +233 -0
- package/src/components/editor/room-labels.test.ts +850 -0
- package/src/components/editor/room-labels.tsx +1890 -0
- package/src/components/editor/room-transform-ghost.tsx +256 -0
- package/src/components/editor/room-webgpu-materials.test.ts +27 -0
- package/src/components/editor/selection-manager.tsx +474 -419
- package/src/components/editor/slab-hole-highlights.tsx +5 -2
- package/src/components/editor/snapshot-capture-overlay.tsx +7 -2
- package/src/components/editor/snapshot-capture.test.ts +119 -60
- package/src/components/editor/snapshot-capture.ts +36 -5
- package/src/components/editor/thumbnail-generator.test.ts +654 -0
- package/src/components/editor/thumbnail-generator.tsx +1103 -223
- package/src/components/editor/use-floorplan-background-placement.ts +34 -12
- package/src/components/editor/vector-edge-extractor.tsx +121 -0
- package/src/components/editor/views/host-view.tsx +61 -0
- package/src/components/editor/views/plugins-view.tsx +663 -0
- package/src/components/editor/views/scene-region.tsx +59 -0
- package/src/components/editor/views/use-editor-views.ts +57 -0
- package/src/components/editor/views/view-bar.test.tsx +54 -0
- package/src/components/editor/views/view-bar.tsx +343 -0
- package/src/components/editor/wall-justification.test.ts +140 -0
- package/src/components/editor/wall-move-side-handles.tsx +43 -142
- package/src/components/editor/wall-push-arrow.tsx +92 -0
- package/src/components/editor/wall-region-handles.tsx +509 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +8 -4
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +8 -4
- package/src/components/editor-2d/floorplan-group-move.tsx +3 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.test.tsx +86 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +290 -0
- package/src/components/editor-2d/floorplan-registered-tool-layer.tsx +2 -2
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +11 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +116 -106
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.test.ts +156 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +278 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +77 -0
- package/src/components/editor-2d/renderers/{floorplan-draft-wall-measurement.tsx → floorplan-draft-measurement.tsx} +8 -8
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +4 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +38 -8
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +319 -233
- package/src/components/editor-2d/renderers/floorplan-reveal.test.tsx +254 -0
- package/src/components/editor-2d/renderers/floorplan-reveal.ts +141 -0
- package/src/components/editor-2d/svg-paths.ts +12 -15
- package/src/components/point-ask/bubble.tsx +538 -0
- package/src/components/point-ask/hover-chip.tsx +91 -0
- package/src/components/point-ask/mode-pill.tsx +92 -0
- package/src/components/point-ask/optional-motion.ts +22 -0
- package/src/components/point-ask/outline-corners.tsx +93 -0
- package/src/components/point-ask/pins.tsx +711 -0
- package/src/components/point-ask/point-ask-layer.tsx +83 -0
- package/src/components/point-ask/point-ask-styles.ts +105 -0
- package/src/components/point-ask/region-marquee-styles.ts +15 -0
- package/src/components/point-ask/region-marquee.tsx +64 -0
- package/src/components/procedural-items/inspector.tsx +40 -15
- package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +12 -2
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.test.ts +97 -14
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +18 -18
- package/src/components/systems/roof/roof-edit-system.tsx +1 -0
- package/src/components/systems/zone/zone-system.test.ts +47 -0
- package/src/components/systems/zone/zone-system.tsx +29 -68
- package/src/components/tools/distribution/connection-compatibility.test.ts +34 -0
- package/src/components/tools/distribution/connection-compatibility.ts +43 -0
- package/src/components/tools/distribution/distribution-public.ts +9 -0
- package/src/components/tools/distribution/distribution-run-contract.test.ts +26 -0
- package/src/components/tools/distribution/distribution-run-contract.ts +94 -0
- package/src/components/tools/distribution/distribution-run-tool.test.ts +241 -0
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +125 -0
- package/src/components/tools/distribution/distribution-run-tool.tsx +1323 -0
- package/src/components/tools/distribution/draw-alignment.ts +35 -0
- package/src/components/tools/distribution/ports.test.ts +56 -0
- package/src/components/tools/distribution/ports.ts +378 -0
- package/src/components/tools/distribution/run-cursor.test.ts +135 -0
- package/src/components/tools/distribution/run-cursor.ts +36 -0
- package/src/components/tools/distribution/run-direction-feedback.test.ts +60 -0
- package/src/components/tools/distribution/run-direction-feedback.tsx +251 -0
- package/src/components/tools/distribution/run-port-snap.test.ts +79 -0
- package/src/components/tools/distribution/run-port-snap.ts +25 -0
- package/src/components/tools/distribution/run-screen-direction.test.ts +23 -0
- package/src/components/tools/distribution/run-screen-direction.ts +30 -0
- package/src/components/tools/elevator/elevator-tool.tsx +3 -6
- package/src/components/tools/elevator/move-elevator-tool.tsx +2 -3
- package/src/components/tools/item/item-surface-strategy-resolver.test.ts +67 -68
- package/src/components/tools/item/placement-history.test.tsx +512 -0
- package/src/components/tools/item/placement-strategies.test.ts +46 -1
- package/src/components/tools/item/placement-strategies.ts +11 -10
- package/src/components/tools/item/shelf-surface-strategy-resolver.test.ts +56 -56
- package/src/components/tools/item/use-draft-node.test.tsx +432 -1
- package/src/components/tools/item/use-draft-node.ts +166 -95
- package/src/components/tools/item/use-placement-coordinator.tsx +148 -95
- package/src/components/tools/paint-region/use-paint-tint.ts +37 -0
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +466 -0
- package/src/components/tools/registry/item-surface-move.test.ts +62 -63
- package/src/components/tools/registry/item-surface-move.ts +2 -0
- package/src/components/tools/registry/item-surface-resolver.test.ts +26 -26
- package/src/components/tools/registry/move-registry-node-tool.test.ts +268 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +66 -30
- package/src/components/tools/select/box-select-tool.tsx +2 -12
- package/src/components/tools/select/plane-box-select-tool.test.tsx +79 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +35 -22
- package/src/components/tools/select/select-candidates.test.ts +37 -4
- package/src/components/tools/select/select-candidates.ts +15 -11
- package/src/components/tools/shared/cursor-sphere.tsx +36 -12
- package/src/components/tools/site/site-boundary-editor.tsx +1 -2
- package/src/components/tools/tool-manager.tsx +59 -24
- package/src/components/tools/wall/wall-drafting.test.ts +175 -47
- package/src/components/tools/zone/zone-tool.tsx +4 -12
- package/src/components/ui/action-menu/action-button.tsx +9 -1
- package/src/components/ui/action-menu/camera-actions.tsx +9 -4
- package/src/components/ui/action-menu/control-modes.tsx +15 -42
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +32 -0
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +36 -0
- package/src/components/ui/action-menu/index.tsx +56 -33
- package/src/components/ui/action-menu/measurement-control.tsx +14 -19
- package/src/components/ui/action-menu/placement.ts +20 -0
- package/src/components/ui/action-menu/point-ask-button.tsx +52 -0
- package/src/components/ui/action-menu/view-toggles.tsx +47 -42
- package/src/components/ui/build-panel/build-panel.tsx +242 -0
- package/src/components/ui/command-palette/editor-commands.tsx +7 -42
- package/src/components/ui/command-palette/index.tsx +50 -39
- package/src/components/ui/command-palette/ranked-groups.test.ts +31 -0
- package/src/components/ui/controls/action-button.tsx +5 -2
- package/src/components/ui/controls/finish-swatch.tsx +110 -0
- package/src/components/ui/controls/material-paint-panel.tsx +97 -26
- package/src/components/ui/controls/material-picker.tsx +4 -1
- package/src/components/ui/controls/metric-control.tsx +1 -1
- package/src/components/ui/controls/scene-material-list.tsx +4 -32
- package/src/components/ui/controls/segmented-control.tsx +21 -8
- package/src/components/ui/controls/select-control.tsx +65 -0
- package/src/components/ui/controls/slider-control.tsx +1 -1
- package/src/components/ui/controls/toggle-control.tsx +3 -3
- package/src/components/ui/controls/tool-options-panel.tsx +1 -1
- package/src/components/ui/floating-level-selector.tsx +159 -59
- package/src/components/ui/helpers/building-helper.tsx +4 -1
- package/src/components/ui/helpers/contextual-helper-panel.tsx +181 -72
- package/src/components/ui/helpers/helper-manager.test.tsx +121 -0
- package/src/components/ui/helpers/helper-manager.tsx +331 -14
- package/src/components/ui/helpers/item-helper.tsx +17 -1
- package/src/components/ui/helpers/registered-tool-helper.tsx +8 -1
- package/src/components/ui/icon-ref.tsx +45 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/node-icon-image.tsx +16 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +28 -22
- package/src/components/ui/panels/floor-foundation-panel.tsx +551 -0
- package/src/components/ui/panels/floor-opening-panel.tsx +143 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +4 -4
- package/src/components/ui/panels/mobile-selection-bar.tsx +8 -5
- package/src/components/ui/panels/multi-field-value.test.ts +26 -3
- package/src/components/ui/panels/multi-field-value.ts +6 -3
- package/src/components/ui/panels/multi-parametric-inspector.tsx +52 -2
- package/src/components/ui/panels/multi-selection-panel.tsx +161 -5
- package/src/components/ui/panels/node-display.ts +8 -3
- package/src/components/ui/panels/panel-manager.tsx +103 -68
- package/src/components/ui/panels/panel-wrapper.tsx +130 -62
- package/src/components/ui/panels/parametric-field-control.tsx +3 -3
- package/src/components/ui/panels/parametric-inspector.tsx +7 -7
- package/src/components/ui/panels/reference-panel.tsx +2 -3
- package/src/components/ui/panels/room-construction-rows.tsx +774 -0
- package/src/components/ui/panels/room-name-options.test.ts +55 -0
- package/src/components/ui/panels/room-name-options.ts +47 -0
- package/src/components/ui/panels/room-openings-field.tsx +110 -0
- package/src/components/ui/panels/room-panel.tsx +790 -0
- package/src/components/ui/panels/shape-choice.tsx +58 -0
- package/src/components/ui/panels/wall-region-list.tsx +109 -0
- package/src/components/ui/primitives/badge.tsx +8 -0
- package/src/components/ui/primitives/color-dot.tsx +36 -24
- package/src/components/ui/primitives/sidebar.tsx +3 -1
- package/src/components/ui/right-stack.test.ts +29 -0
- package/src/components/ui/right-stack.tsx +164 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +1 -1
- package/src/components/ui/sidebar/icon-rail.tsx +8 -3
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +6 -6
- package/src/components/ui/sidebar/panels/settings-panel/animation-speed-setting.tsx +40 -0
- package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +7 -8
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.test.tsx +170 -0
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +92 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +138 -27
- package/src/components/ui/sidebar/panels/settings-panel/interface-theme.test.tsx +20 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +5 -5
- package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +4 -10
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -11
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -4
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +197 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +24 -11
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +181 -223
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +30 -8
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +4 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +1 -4
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +21 -13
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +13 -37
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -3
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +9 -4
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +2 -4
- package/src/components/ui/sidebar/tab-bar.tsx +14 -4
- package/src/components/ui/sidebar/use-plugin-panels.tsx +15 -5
- package/src/components/viewer/floorplan-compass-button.tsx +9 -1
- package/src/components/viewer/floorplan-preview.tsx +5 -6
- package/src/components/viewer/viewer-controls-bar.tsx +18 -6
- package/src/components/viewer/viewer-hover-label.tsx +34 -0
- package/src/components/viewer/viewer-rooms.tsx +191 -0
- package/src/components/viewer/viewer-scene-header.tsx +181 -145
- package/src/components/viewer/viewer-selection-manager.tsx +124 -0
- package/src/components/viewer/viewer-stage.tsx +2 -2
- package/src/components/viewer-zone-system.tsx +3 -8
- package/src/hooks/use-auto-save.integration.test.tsx +215 -43
- package/src/hooks/use-auto-save.ts +60 -9
- package/src/hooks/use-ceiling-events.test.ts +123 -118
- package/src/hooks/use-grid-events.test.ts +105 -105
- package/src/hooks/use-keyboard.test.ts +243 -19
- package/src/hooks/use-keyboard.ts +118 -83
- package/src/hooks/use-open-wall-ends.test.ts +99 -0
- package/src/hooks/use-open-wall-ends.ts +238 -0
- package/src/hooks/use-placement-notice.test.ts +71 -0
- package/src/hooks/use-placement-notice.ts +73 -0
- package/src/hooks/use-selected-room.ts +143 -0
- package/src/index.tsx +312 -58
- package/src/lib/__fixtures__/owner-victor-seattle-parking.json +1 -0
- package/src/lib/__fixtures__/owner-villa-aurelia-basement.json +1 -0
- package/src/lib/add-storey.test.ts +177 -0
- package/src/lib/add-storey.ts +59 -0
- package/src/lib/below-grade.test.tsx +171 -0
- package/src/lib/below-grade.ts +133 -0
- package/src/lib/camera-facing.test.ts +24 -0
- package/src/lib/camera-facing.ts +24 -0
- package/src/lib/ceiling-edit-session.test.ts +321 -0
- package/src/lib/ceiling-edit-session.ts +206 -0
- package/src/lib/ceiling-region-session.test.ts +179 -0
- package/src/lib/continuation.test.ts +19 -1
- package/src/lib/continuation.ts +25 -4
- package/src/lib/direct-manipulation.ts +2 -0
- package/src/lib/door-interaction.ts +14 -0
- package/src/lib/download-project-file.ts +17 -0
- package/src/lib/editor-level-display.test.ts +96 -0
- package/src/lib/editor-level-display.ts +55 -0
- package/src/lib/editor-views.ts +178 -0
- package/src/lib/export-geometry-wait.test.ts +90 -0
- package/src/lib/export-texture-utils.ts +2 -4
- package/src/lib/floor-edit-session.ts +153 -0
- package/src/lib/floor-footprints.test.ts +563 -0
- package/src/lib/floor-footprints.ts +395 -0
- package/src/lib/floor-foundation-support.test.ts +284 -0
- package/src/lib/floor-opening-draft.ts +218 -0
- package/src/lib/floor-openings.test.ts +216 -0
- package/src/lib/floor-region-geometry.ts +191 -0
- package/src/lib/floor-region-session.test.ts +485 -0
- package/src/lib/floor-region-session.ts +589 -0
- package/src/lib/floor-region-snap.ts +101 -0
- package/src/lib/floor-step-hover.test.ts +32 -0
- package/src/lib/floorplan/annotation-visibility.ts +17 -0
- package/src/lib/floorplan/dimension-drive.test.ts +360 -0
- package/src/lib/floorplan/dimension-drive.ts +479 -0
- package/src/lib/floorplan/floorplan-export.test.ts +12 -8
- package/src/lib/floorplan/floorplan-export.tsx +32 -8
- package/src/lib/floorplan/floorplan-extension.ts +32 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +4 -0
- package/src/lib/floorplan/floorplan-mode.ts +2 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +363 -27
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +177 -8
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +60 -25
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +138 -0
- package/src/lib/floorplan/floorplan-readonly.ts +6 -0
- package/src/lib/floorplan/geometry.ts +13 -6
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/marks.test.ts +213 -0
- package/src/lib/floorplan/marks.ts +238 -0
- package/src/lib/floorplan/open-wall-ends.test.ts +268 -0
- package/src/lib/floorplan/open-wall-ends.ts +162 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Regular.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-GeistMono.txt +92 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-LiberationSans.txt +102 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Regular.ttf +0 -0
- package/src/lib/floorplan/pdfkit-standard-fonts.d.ts +5 -0
- package/src/lib/floorplan/schedules.test.ts +189 -0
- package/src/lib/floorplan/schedules.ts +339 -0
- package/src/lib/floorplan/sheet-export.test.ts +124 -0
- package/src/lib/floorplan/sheet-export.ts +318 -0
- package/src/lib/floorplan/site-plan/build-site-plan-drawing.ts +768 -0
- package/src/lib/floorplan/site-plan/contours.test.ts +43 -0
- package/src/lib/floorplan/site-plan/contributors.ts +97 -0
- package/src/lib/floorplan/site-plan/coverage.ts +230 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.test.ts +15 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.tsx +86 -0
- package/src/lib/floorplan/site-plan/front-edge.test.ts +103 -0
- package/src/lib/floorplan/site-plan/front-edge.ts +157 -0
- package/src/lib/floorplan/site-plan/geometry.test.ts +269 -0
- package/src/lib/floorplan/site-plan/geometry.ts +142 -0
- package/src/lib/floorplan/site-plan/index.ts +55 -0
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +483 -0
- package/src/lib/floorplan/site-plan/site-annotations.ts +1084 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +287 -0
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +138 -0
- package/src/lib/floorplan/site-plan/street-name.test.ts +69 -0
- package/src/lib/floorplan/site-plan/street-name.ts +302 -0
- package/src/lib/floorplan/site-plan/yards.test.ts +70 -0
- package/src/lib/floorplan/types.ts +1 -27
- package/src/lib/follow-pascal-exterior.test-fixture.ts +17 -0
- package/src/lib/follow-pascal-exterior.test.ts +171 -0
- package/src/lib/follow-pascal-exterior.ts +39 -0
- package/src/lib/follow-pascal-presentation.test.ts +203 -0
- package/src/lib/follow-pascal-presentation.ts +129 -0
- package/src/lib/follow-pascal-sight.ts +84 -0
- package/src/lib/follow-pascal-targets.test.ts +406 -0
- package/src/lib/follow-pascal-targets.ts +198 -0
- package/src/lib/follow-pascal.test.ts +350 -0
- package/src/lib/follow-pascal.ts +284 -0
- package/src/lib/fresh-planar-placement.test.ts +148 -0
- package/src/lib/fresh-planar-placement.ts +114 -37
- package/src/lib/geometry-script/author.ts +157 -0
- package/src/lib/geometry-script/client.ts +159 -0
- package/src/lib/geometry-script/finish-scripts.ts +127 -0
- package/src/lib/geometry-script/protocol.ts +13 -0
- package/src/lib/gesture-lifecycle.test.ts +595 -0
- package/src/lib/gesture-lifecycle.ts +290 -0
- package/src/lib/glb-export-zone-holes.test.ts +41 -0
- package/src/lib/glb-export.test.ts +636 -126
- package/src/lib/glb-export.ts +241 -120
- package/src/lib/history.test.ts +18 -7
- package/src/lib/history.ts +7 -0
- package/src/lib/hud-title.ts +109 -0
- package/src/lib/hydration-gated-storage.ts +49 -0
- package/src/lib/ifc-export.test.ts +174 -0
- package/src/lib/ifc-export.ts +201 -0
- package/src/lib/ifc-parts.ts +15 -0
- package/src/lib/inspector-expanded.test.ts +44 -0
- package/src/lib/inspector-expanded.ts +36 -0
- package/src/lib/interaction/scope.ts +22 -0
- package/src/lib/keyboard-pan.test.ts +129 -7
- package/src/lib/keyboard-pan.ts +161 -12
- package/src/lib/level-selection.test.ts +57 -0
- package/src/lib/level-selection.ts +16 -1
- package/src/lib/live-gesture-round-trip.test.ts +360 -0
- package/src/lib/lot/__fixtures__/map-dossier-miami-shores.json +1 -0
- package/src/lib/lot/__fixtures__/map-dossier-stpete.json +1 -0
- package/src/lib/lot/clean-ring.test.ts +187 -0
- package/src/lib/lot/clean-ring.ts +217 -0
- package/src/lib/lot/dossier.test.ts +202 -0
- package/src/lib/lot/dossier.ts +498 -0
- package/src/lib/lot/drop-in.test.ts +326 -0
- package/src/lib/lot/drop-in.ts +392 -0
- package/src/lib/lot/index.ts +43 -0
- package/src/lib/lot/lot-patch.test.ts +340 -0
- package/src/lib/lot/lot-patch.ts +394 -0
- package/src/lib/lot/parcel-provider.ts +43 -0
- package/src/lib/lot/terrain.test.ts +161 -0
- package/src/lib/lot/terrain.ts +266 -0
- package/src/lib/material-catalog-model.ts +3 -1
- package/src/lib/material-paint-panel-model.ts +9 -5
- package/src/lib/material-paint.ts +4 -0
- package/src/lib/measurement-kind.test.ts +6 -8
- package/src/lib/measurements.test.ts +23 -0
- package/src/lib/mezzanine-actions.test.ts +342 -0
- package/src/lib/mezzanine-draft.test.ts +501 -0
- package/src/lib/mezzanine-draft.ts +278 -0
- package/src/lib/mezzanine-messages.ts +26 -0
- package/src/lib/mezzanine-selection.test.ts +207 -0
- package/src/lib/mezzanine-stairs.ts +46 -0
- package/src/lib/model-export.ts +3 -1
- package/src/lib/node-action-movement.ts +17 -6
- package/src/lib/node-display-label.ts +37 -0
- package/src/lib/orbit-floor-clearance.test.ts +201 -0
- package/src/lib/orbit-floor-clearance.ts +154 -0
- package/src/lib/paint-commit-route.test.ts +37 -0
- package/src/lib/paint-commit-route.ts +17 -0
- package/src/lib/paint-eyedropper.test.tsx +165 -0
- package/src/lib/paint-eyedropper.ts +99 -0
- package/src/lib/paint-pass-through.test.ts +122 -0
- package/src/lib/paint-pass-through.ts +78 -0
- package/src/lib/paint-region-hover.ts +25 -0
- package/src/lib/paint-region-mode.ts +154 -0
- package/src/lib/paint-regions.test.ts +166 -0
- package/src/lib/paint-regions.ts +192 -0
- package/src/lib/paint-scope.test.ts +317 -35
- package/src/lib/paint-scope.ts +267 -25
- package/src/lib/panel-rows.ts +21 -0
- package/src/lib/parametric-node-update.ts +16 -7
- package/src/lib/plate-paint-affected.test.ts +300 -0
- package/src/lib/plate-paint-affected.ts +177 -0
- package/src/lib/plugin-chat.ts +65 -0
- package/src/lib/plugin-panels.test.ts +25 -0
- package/src/lib/plugin-panels.ts +94 -0
- package/src/lib/point-ask/__fixtures__/consumer-browser.tsx +76 -0
- package/src/lib/point-ask/__fixtures__/house.ts +81 -0
- package/src/lib/point-ask/ask-created.test.ts +195 -0
- package/src/lib/point-ask/ask-flow.test.ts +380 -0
- package/src/lib/point-ask/build-context.test.ts +173 -0
- package/src/lib/point-ask/build-context.ts +94 -0
- package/src/lib/point-ask/capture-crop.ts +129 -0
- package/src/lib/point-ask/choreography.ts +69 -0
- package/src/lib/point-ask/compare.test.ts +145 -0
- package/src/lib/point-ask/compare.ts +73 -0
- package/src/lib/point-ask/describe-target.test.ts +165 -0
- package/src/lib/point-ask/describe-target.ts +234 -0
- package/src/lib/point-ask/dictation.ts +79 -0
- package/src/lib/point-ask/edge-marker.test.ts +61 -0
- package/src/lib/point-ask/edge-marker.ts +27 -0
- package/src/lib/point-ask/frame-loop.ts +25 -0
- package/src/lib/point-ask/history-marks.test.ts +94 -0
- package/src/lib/point-ask/history-marks.ts +39 -0
- package/src/lib/point-ask/host-api.ts +32 -0
- package/src/lib/point-ask/outline-box.test.ts +30 -0
- package/src/lib/point-ask/outline-box.ts +11 -0
- package/src/lib/point-ask/overlay-metrics.ts +6 -0
- package/src/lib/point-ask/pick.test.ts +220 -0
- package/src/lib/point-ask/pick.ts +121 -0
- package/src/lib/point-ask/pin-machine.test.ts +494 -0
- package/src/lib/point-ask/pin-machine.ts +217 -0
- package/src/lib/point-ask/placement.test.ts +203 -0
- package/src/lib/point-ask/placement.ts +141 -0
- package/src/lib/point-ask/pointer-tracker.ts +34 -0
- package/src/lib/point-ask/projector.ts +83 -0
- package/src/lib/point-ask/region.test.ts +157 -0
- package/src/lib/point-ask/region.ts +136 -0
- package/src/lib/point-ask/retry.test.ts +217 -0
- package/src/lib/point-ask/retry.ts +37 -0
- package/src/lib/point-ask/scene-commit.test.ts +312 -0
- package/src/lib/point-ask/scene-commit.ts +32 -0
- package/src/lib/point-ask/session.ts +1391 -0
- package/src/lib/point-ask/spring-keyframes.test.ts +45 -0
- package/src/lib/point-ask/spring-keyframes.ts +38 -0
- package/src/lib/point-ask/spring.test.ts +63 -0
- package/src/lib/point-ask/spring.ts +107 -0
- package/src/lib/point-ask/suggestions.test.ts +80 -0
- package/src/lib/point-ask/suggestions.ts +125 -0
- package/src/lib/point-ask/target-scope.test.ts +622 -0
- package/src/lib/point-ask/target-scope.ts +338 -0
- package/src/lib/point-ask/types.ts +48 -0
- package/src/lib/portable-export.test.ts +34 -1
- package/src/lib/portable-export.ts +119 -53
- package/src/lib/print-feature-thickness.ts +10 -1
- package/src/lib/print-roof-solids.test.ts +39 -1
- package/src/lib/print-roof-solids.ts +43 -10
- package/src/lib/print-shell-compiler-manifold-core.ts +1 -1
- package/src/lib/print-shell-compiler.ts +1 -0
- package/src/lib/registered-draft-snap.ts +12 -0
- package/src/lib/roof-duplication.ts +10 -2
- package/src/lib/room-assembly-overlay.test.ts +275 -0
- package/src/lib/room-assembly-overlay.ts +265 -0
- package/src/lib/room-built-on.test.ts +379 -0
- package/src/lib/room-built-on.ts +138 -0
- package/src/lib/room-construction-commands.ts +712 -0
- package/src/lib/room-construction.test.ts +746 -0
- package/src/lib/room-construction.ts +385 -0
- package/src/lib/room-controls-phase6.test.ts +630 -0
- package/src/lib/room-divide-session.ts +523 -0
- package/src/lib/room-handle-drag.ts +1068 -0
- package/src/lib/room-name-catalog.test.ts +90 -0
- package/src/lib/room-name-catalog.ts +168 -0
- package/src/lib/room-push-dimensions.test.ts +311 -0
- package/src/lib/room-push-dimensions.ts +251 -0
- package/src/lib/room-selection-commands.ts +62 -0
- package/src/lib/room-selection.test.ts +1017 -0
- package/src/lib/room-selection.ts +417 -0
- package/src/lib/room-structure-commands.ts +94 -0
- package/src/lib/room-structure.test.ts +921 -0
- package/src/lib/room-transform-session.ts +570 -0
- package/src/lib/room-zone-routing.test.ts +294 -0
- package/src/lib/room-zone-routing.ts +197 -0
- package/src/lib/scene-clipboard.test.ts +610 -1
- package/src/lib/scene-clipboard.ts +269 -58
- package/src/lib/scene-material-refs.test.ts +79 -0
- package/src/lib/scene-material-refs.ts +79 -0
- package/src/lib/scene.test.ts +24 -36
- package/src/lib/scene.ts +33 -57
- package/src/lib/selection-routing.test.ts +129 -45
- package/src/lib/selection-routing.ts +54 -75
- package/src/lib/session-writes.test.ts +120 -0
- package/src/lib/session-writes.ts +205 -0
- package/src/lib/sfx-bus.ts +13 -0
- package/src/lib/sfx-player.test.ts +70 -9
- package/src/lib/sfx-player.ts +6 -0
- package/src/lib/sidebar-panel.ts +62 -0
- package/src/lib/site-boundary.test.ts +4 -6
- package/src/lib/site-boundary.ts +1 -1
- package/src/lib/snapping-mode.test.ts +4 -0
- package/src/lib/snapping-mode.ts +8 -1
- package/src/lib/stair-levels.test.ts +25 -0
- package/src/lib/stair-levels.ts +22 -3
- package/src/lib/terrace-draft.test.ts +145 -0
- package/src/lib/terrace-draft.ts +214 -0
- package/src/lib/tool-cursor-icon.test.ts +16 -0
- package/src/lib/tool-cursor-icon.ts +11 -0
- package/src/lib/typing-target.ts +9 -0
- package/src/lib/units.ts +77 -39
- package/src/lib/vector-edges.test.ts +58 -0
- package/src/lib/vector-edges.ts +400 -0
- package/src/lib/viewer-selection.test.ts +577 -0
- package/src/lib/viewer-selection.ts +580 -0
- package/src/lib/wall-draw-variant.test.ts +71 -0
- package/src/lib/wall-draw-variant.ts +91 -0
- package/src/lib/wall-paint-region-session.ts +246 -0
- package/src/lib/wall-paint-region.test.ts +373 -0
- package/src/lib/wall-placement-pointer.test.ts +42 -0
- package/src/lib/wall-placement-pointer.ts +57 -0
- package/src/lib/wall-polygon-draft.test.ts +262 -0
- package/src/lib/wall-polygon-draft.ts +286 -0
- package/src/lib/wall-push.test.ts +453 -0
- package/src/lib/wall-region-face.ts +352 -0
- package/src/lib/wall-region-handles.test.ts +304 -0
- package/src/lib/wall-region-handles.ts +368 -0
- package/src/lib/wall-region-list.test.ts +119 -0
- package/src/lib/wall-region-list.ts +136 -0
- package/src/lib/wall-region-snap.ts +110 -0
- package/src/lib/window-changes.ts +35 -0
- package/src/lib/window-interaction.ts +14 -0
- package/src/lib/zone-content.ts +4 -1
- package/src/lib/zone-name.test.ts +17 -0
- package/src/lib/zone-name.ts +17 -0
- package/src/store/opens-in-select-mode.test.ts +223 -0
- package/src/store/paint-mode.test.ts +188 -0
- package/src/store/terrain-sculpt-mode.test.ts +19 -21
- package/src/store/tool-mode.test.ts +137 -6
- package/src/store/use-audio.test.ts +146 -0
- package/src/store/use-audio.tsx +127 -3
- package/src/store/use-construction-reveal.test.ts +173 -0
- package/src/store/use-construction-reveal.ts +145 -0
- package/src/store/use-corner-snap-hint.test.ts +24 -0
- package/src/store/use-corner-snap-hint.ts +47 -0
- package/src/store/use-delete-confirmation.ts +28 -1
- package/src/store/use-drawing-view.test.ts +24 -3
- package/src/store/use-drawing-view.ts +29 -1
- package/src/store/use-editor.tsx +432 -321
- package/src/store/use-floorplan-draft-preview.ts +13 -0
- package/src/store/use-floorplan-marquee.ts +12 -2
- package/src/store/use-follow-pascal.test.ts +62 -0
- package/src/store/use-follow-pascal.ts +53 -0
- package/src/store/use-point-ask.ts +247 -0
- package/src/store/use-quick-measurement-hud.ts +3 -3
- package/src/store/use-stair-build-preview.ts +33 -5
- package/src/store/use-wall-move-ghosts.ts +4 -2
- package/src/store/use-wall-region-handles-selection.test.ts +222 -0
- package/src/store/use-wall-region-handles-selection.ts +139 -0
- package/src/store/view-layout.test.ts +201 -0
- package/src/store/view-layout.ts +199 -0
- package/src/test-utils/immediate-animation-frames.ts +16 -0
- package/src/test-utils/live-gesture-round-trip.ts +224 -0
- package/src/test-utils/render-current-markup.tsx +16 -0
- package/src/test-utils/selection-harness.ts +82 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +0 -499
- package/src/components/systems/zone/zone-label-editor-system.tsx +0 -333
- package/src/components/tools/fence/fence-drafting.test.ts +0 -100
- package/src/components/tools/fence/fence-drafting.ts +0 -266
- package/src/components/tools/stair/stair-click-guard.test.ts +0 -58
- package/src/components/tools/stair/stair-click-guard.ts +0 -72
- package/src/components/tools/stair/stair-defaults.ts +0 -18
- package/src/components/tools/stair/stair-tool.tsx +0 -634
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +0 -218
- package/src/components/viewer/viewer-units-panel.tsx +0 -116
- package/src/lib/floorplan/stairs.ts +0 -489
- package/src/lib/level-duplication.test.ts +0 -144
- package/src/lib/level-duplication.ts +0 -195
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { getSceneTheme, useViewer } from '@pascal-app/viewer'
|
|
4
4
|
import { type ReactNode, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
|
5
|
+
import { useShownSidebarPanel } from '../../lib/sidebar-panel'
|
|
5
6
|
import useEditor from '../../store/use-editor'
|
|
6
7
|
import { MobileTabBar } from '../ui/sidebar/mobile-tab-bar'
|
|
7
8
|
import type { SidebarTab } from '../ui/sidebar/tab-bar'
|
|
8
9
|
import { BottomSheet, type BottomSheetHandle } from './bottom-sheet'
|
|
10
|
+
import { useSceneSpan } from './views/scene-region'
|
|
11
|
+
import { ViewTabs } from './views/view-bar'
|
|
9
12
|
|
|
10
13
|
const MIN_SNAP = 0
|
|
11
14
|
const MAX_SNAP = 1
|
|
@@ -40,6 +43,7 @@ export interface EditorLayoutMobileProps {
|
|
|
40
43
|
viewerToolbarRight?: ReactNode
|
|
41
44
|
viewerContent: ReactNode
|
|
42
45
|
overlays?: ReactNode
|
|
46
|
+
viewBar?: boolean
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
export function EditorLayoutMobile({
|
|
@@ -51,9 +55,11 @@ export function EditorLayoutMobile({
|
|
|
51
55
|
viewerToolbarRight,
|
|
52
56
|
viewerContent,
|
|
53
57
|
overlays,
|
|
58
|
+
viewBar = true,
|
|
54
59
|
}: EditorLayoutMobileProps) {
|
|
60
|
+
const hasScene = useSceneSpan() !== null
|
|
55
61
|
const isCaptureMode = useEditor((s) => s.isCaptureMode)
|
|
56
|
-
const activePanel =
|
|
62
|
+
const activePanel = useShownSidebarPanel(sidebarTabs)
|
|
57
63
|
const setActivePanel = useEditor((s) => s.setActiveSidebarPanel)
|
|
58
64
|
const panelSheetHeight = useEditor((s) => s.mobilePanelSheetHeight)
|
|
59
65
|
const isDark = useViewer((s) => getSceneTheme(s.sceneTheme).appearance === 'dark')
|
|
@@ -70,30 +76,18 @@ export function EditorLayoutMobile({
|
|
|
70
76
|
|
|
71
77
|
const currentTab = sidebarTabs.find((t) => t.id === activePanel)
|
|
72
78
|
|
|
73
|
-
//
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (sidebarTabs.length > 0 && !sidebarTabs.some((t) => t.id === activePanel)) {
|
|
76
|
-
setActivePanel(sidebarTabs[0]!.id)
|
|
77
|
-
}
|
|
78
|
-
}, [sidebarTabs, activePanel, setActivePanel])
|
|
79
|
-
|
|
80
|
-
// Sync editor phase / mode with the active tab:
|
|
79
|
+
// Sync the editor mode with the active tab:
|
|
81
80
|
// - Entering Chat always drops to Select (chat is a composing context).
|
|
82
|
-
// -
|
|
83
|
-
//
|
|
84
|
-
//
|
|
81
|
+
// - Leaving Items with the item tool still armed exits the build mode.
|
|
82
|
+
// Arming the item tool on entering Items belongs to the tap (`handleTabPress`):
|
|
83
|
+
// a tab restored on load opens in select mode.
|
|
85
84
|
useEffect(() => {
|
|
86
|
-
const { armToolMode,
|
|
85
|
+
const { armToolMode, mode, tool } = useEditor.getState()
|
|
87
86
|
if (activePanel === 'ai' && mode === 'build') {
|
|
88
87
|
armToolMode({ mode: 'select' })
|
|
89
88
|
return
|
|
90
89
|
}
|
|
91
|
-
if (activePanel
|
|
92
|
-
if (phase !== 'furnish') setPhase('furnish')
|
|
93
|
-
if (mode !== 'build') armToolMode({ mode: 'build', tool: 'item' })
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
if (phase === 'furnish' && mode === 'build') {
|
|
90
|
+
if (activePanel !== 'items' && mode === 'build' && tool === 'item') {
|
|
97
91
|
armToolMode({ mode: 'select' })
|
|
98
92
|
}
|
|
99
93
|
}, [activePanel])
|
|
@@ -148,9 +142,17 @@ export function EditorLayoutMobile({
|
|
|
148
142
|
if (middleH <= 0) return
|
|
149
143
|
const tab = sidebarTabs.find((t) => t.id === id)
|
|
150
144
|
if (!tab) return
|
|
145
|
+
if (tab.onSelect) {
|
|
146
|
+
tab.onSelect()
|
|
147
|
+
return
|
|
148
|
+
}
|
|
151
149
|
const defaultPx = getDefaultSnap(tab) * middleH
|
|
152
150
|
if (id !== activePanel) {
|
|
153
151
|
setActivePanel(id)
|
|
152
|
+
// Tapping Items arms the item tool, as F does on desktop.
|
|
153
|
+
if (id === 'items' && useEditor.getState().mode !== 'build') {
|
|
154
|
+
useEditor.getState().armToolMode({ mode: 'build', tool: 'item' })
|
|
155
|
+
}
|
|
154
156
|
sheetRef.current?.snapTo(defaultPx)
|
|
155
157
|
return
|
|
156
158
|
}
|
|
@@ -212,7 +214,7 @@ export function EditorLayoutMobile({
|
|
|
212
214
|
}, [panelSheetHeight, committedSheetH])
|
|
213
215
|
|
|
214
216
|
return (
|
|
215
|
-
<div className="
|
|
217
|
+
<div className="flex h-full w-full flex-col bg-sidebar text-foreground">
|
|
216
218
|
{navbarSlot}
|
|
217
219
|
|
|
218
220
|
<div
|
|
@@ -223,14 +225,23 @@ export function EditorLayoutMobile({
|
|
|
223
225
|
{/* Viewer column: sized by committed sheet height */}
|
|
224
226
|
<div className="absolute inset-x-0 top-0 overflow-hidden" style={{ height: viewerHeight }}>
|
|
225
227
|
<div className="relative h-full w-full">
|
|
226
|
-
{(viewerToolbarLeft || viewerToolbarRight) && !isCaptureMode && (
|
|
228
|
+
{(viewBar || viewerToolbarLeft || viewerToolbarRight) && !isCaptureMode && (
|
|
227
229
|
<div className="pointer-events-none absolute top-3 right-3 left-3 z-20 flex items-center justify-between gap-2">
|
|
228
|
-
<div className="
|
|
229
|
-
{
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
<div className="flex items-center gap-2">
|
|
231
|
+
{viewBar && (
|
|
232
|
+
<div data-view-bar={0}>
|
|
233
|
+
<ViewTabs className="shadow-elevation-4" pane={0} />
|
|
234
|
+
</div>
|
|
235
|
+
)}
|
|
236
|
+
<div className="pointer-events-auto flex items-center gap-2">
|
|
237
|
+
{viewerToolbarLeft}
|
|
238
|
+
</div>
|
|
233
239
|
</div>
|
|
240
|
+
{hasScene && (
|
|
241
|
+
<div className="pointer-events-auto flex items-center gap-2">
|
|
242
|
+
{viewerToolbarRight}
|
|
243
|
+
</div>
|
|
244
|
+
)}
|
|
234
245
|
</div>
|
|
235
246
|
)}
|
|
236
247
|
<div className="relative h-full w-full overflow-hidden">{viewerContent}</div>
|
|
@@ -2,13 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
import { type ReactNode, useCallback, useEffect, useRef } from 'react'
|
|
4
4
|
import { useIsMobile } from '../../hooks/use-mobile'
|
|
5
|
+
import {
|
|
6
|
+
openSidebarPanel,
|
|
7
|
+
SIDEBAR_MIN_WIDTH,
|
|
8
|
+
setSidebarTabIds,
|
|
9
|
+
showSidebarPanel,
|
|
10
|
+
useShownSidebarPanel,
|
|
11
|
+
} from '../../lib/sidebar-panel'
|
|
5
12
|
import useEditor from '../../store/use-editor'
|
|
6
13
|
|
|
7
14
|
import { useSidebarStore } from '../ui/primitives/sidebar'
|
|
8
15
|
import { IconRail, type SidebarTab } from '../ui/sidebar/tab-bar'
|
|
9
16
|
import { EditorLayoutMobile } from './editor-layout-mobile'
|
|
17
|
+
import { useSceneSpan } from './views/scene-region'
|
|
18
|
+
import { ViewBarRow } from './views/view-bar'
|
|
10
19
|
|
|
11
|
-
const SIDEBAR_MIN_WIDTH = 300
|
|
12
20
|
const SIDEBAR_MAX_WIDTH = 800
|
|
13
21
|
const SIDEBAR_COLLAPSE_THRESHOLD = 220
|
|
14
22
|
// Matches the `w-14` rail in <IconRail>; the resize math is relative to it.
|
|
@@ -31,27 +39,49 @@ function LeftColumn({
|
|
|
31
39
|
const setWidth = useSidebarStore((s) => s.setWidth)
|
|
32
40
|
const isDragging = useSidebarStore((s) => s.isDragging)
|
|
33
41
|
const setIsDragging = useSidebarStore((s) => s.setIsDragging)
|
|
34
|
-
const activePanel =
|
|
42
|
+
const activePanel = useShownSidebarPanel(tabs)
|
|
35
43
|
const setActivePanel = useEditor((s) => s.setActiveSidebarPanel)
|
|
36
44
|
|
|
37
45
|
const isResizing = useRef(false)
|
|
38
46
|
|
|
39
|
-
//
|
|
47
|
+
// Publish the rail's tabs so keyboard shortcuts (B, P) can open a panel.
|
|
40
48
|
useEffect(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
setSidebarTabIds(tabs.map((tab) => tab.id))
|
|
50
|
+
return () => setSidebarTabIds([])
|
|
51
|
+
}, [tabs])
|
|
52
|
+
|
|
53
|
+
// A stage entry whose surface has left the stage (its view closed from the
|
|
54
|
+
// view bar) hands the rail back to the panel that was open before it.
|
|
55
|
+
const lastPanelTab = useRef<string | null>(null)
|
|
56
|
+
const activeTab = tabs.find((t) => t.id === activePanel)
|
|
57
|
+
if (activeTab && !activeTab.noPanel) lastPanelTab.current = activeTab.id
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (activeTab?.stageActive !== false) return
|
|
60
|
+
const fallback = tabs.find((t) => t.id === lastPanelTab.current) ?? tabs.find((t) => !t.noPanel)
|
|
61
|
+
if (fallback) setActivePanel(fallback.id)
|
|
62
|
+
}, [activeTab, tabs, setActivePanel])
|
|
45
63
|
|
|
46
|
-
// Leaving the items tab
|
|
64
|
+
// Leaving the items tab with the item tool in hand drops back to select mode
|
|
47
65
|
useEffect(() => {
|
|
48
66
|
if (activePanel === 'items') return
|
|
49
|
-
const {
|
|
50
|
-
if (
|
|
67
|
+
const { mode, tool, setMode } = useEditor.getState()
|
|
68
|
+
if (mode === 'build' && tool === 'item') {
|
|
51
69
|
setMode('select')
|
|
52
70
|
}
|
|
53
71
|
}, [activePanel])
|
|
54
72
|
|
|
73
|
+
// Paint mode entered without the panel (command palette, a material's "paint
|
|
74
|
+
// with") brings the host's Paint panel along, so the rail reflects the mode.
|
|
75
|
+
useEffect(
|
|
76
|
+
() =>
|
|
77
|
+
useEditor.subscribe((state, prev) => {
|
|
78
|
+
if (state.mode !== prev.mode && state.mode === 'material-paint') {
|
|
79
|
+
openSidebarPanel(['paint'])
|
|
80
|
+
}
|
|
81
|
+
}),
|
|
82
|
+
[],
|
|
83
|
+
)
|
|
84
|
+
|
|
55
85
|
// Closing (collapsing) the sidebar disarms any build tool back to select
|
|
56
86
|
useEffect(() => {
|
|
57
87
|
if (!isCollapsed) return
|
|
@@ -72,20 +102,20 @@ function LeftColumn({
|
|
|
72
102
|
[setIsDragging],
|
|
73
103
|
)
|
|
74
104
|
|
|
75
|
-
// Rail click: reopen a collapsed panel, collapse when
|
|
76
|
-
// tab, otherwise switch tabs.
|
|
77
|
-
// up to the minimum so the panel always returns to a usable size.
|
|
105
|
+
// Rail click: reopen a collapsed panel (at a usable width), collapse when
|
|
106
|
+
// re-clicking the open tab, otherwise switch tabs.
|
|
78
107
|
const handleRailClick = useCallback(
|
|
79
108
|
(id: string) => {
|
|
109
|
+
const tab = tabs.find((t) => t.id === id)
|
|
110
|
+
if (id !== activePanel) tabs.find((t) => t.id === activePanel)?.onDeselect?.()
|
|
111
|
+
tab?.onSelect?.()
|
|
80
112
|
// noPanel tabs drive the stage, not the panel — leave collapse state alone.
|
|
81
|
-
if (
|
|
113
|
+
if (tab?.noPanel) {
|
|
82
114
|
setActivePanel(id)
|
|
83
115
|
return
|
|
84
116
|
}
|
|
85
117
|
if (isCollapsed) {
|
|
86
|
-
|
|
87
|
-
if (width < SIDEBAR_MIN_WIDTH) setWidth(SIDEBAR_MIN_WIDTH)
|
|
88
|
-
setActivePanel(id)
|
|
118
|
+
showSidebarPanel(id)
|
|
89
119
|
return
|
|
90
120
|
}
|
|
91
121
|
if (id === activePanel) {
|
|
@@ -94,7 +124,7 @@ function LeftColumn({
|
|
|
94
124
|
}
|
|
95
125
|
setActivePanel(id)
|
|
96
126
|
},
|
|
97
|
-
[tabs, isCollapsed,
|
|
127
|
+
[tabs, isCollapsed, activePanel, setIsCollapsed, setActivePanel],
|
|
98
128
|
)
|
|
99
129
|
|
|
100
130
|
useEffect(() => {
|
|
@@ -159,59 +189,97 @@ function LeftColumn({
|
|
|
159
189
|
|
|
160
190
|
// ── Right column: viewer area with toolbar ───────────────────────────────────
|
|
161
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Host toolbars floating over the stage. The right one carries scene controls
|
|
194
|
+
* (wall mode, display), so it sits at the right edge of the scene panes; the
|
|
195
|
+
* left one floats only when there is no view bar row to carry it.
|
|
196
|
+
*/
|
|
197
|
+
function StageToolbar({
|
|
198
|
+
toolbarLeft,
|
|
199
|
+
toolbarRight,
|
|
200
|
+
}: {
|
|
201
|
+
toolbarLeft?: ReactNode
|
|
202
|
+
toolbarRight?: ReactNode
|
|
203
|
+
}) {
|
|
204
|
+
const scene = useSceneSpan()
|
|
205
|
+
return (
|
|
206
|
+
<div className="pointer-events-none absolute top-3 right-0 left-0 z-20 h-8">
|
|
207
|
+
{toolbarLeft && (
|
|
208
|
+
<div className="pointer-events-auto absolute top-0 left-3 flex items-center gap-2">
|
|
209
|
+
{toolbarLeft}
|
|
210
|
+
</div>
|
|
211
|
+
)}
|
|
212
|
+
{toolbarRight && scene && (
|
|
213
|
+
<div
|
|
214
|
+
className="pointer-events-auto absolute top-0 flex items-center gap-2"
|
|
215
|
+
style={{ right: `calc(${(1 - scene.right) * 100}% + 12px)` }}
|
|
216
|
+
>
|
|
217
|
+
{toolbarRight}
|
|
218
|
+
</div>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
162
224
|
function RightColumn({
|
|
163
225
|
toolbarLeft,
|
|
164
226
|
toolbarRight,
|
|
227
|
+
viewBar,
|
|
165
228
|
children,
|
|
166
229
|
overlays,
|
|
167
230
|
stageOverlay,
|
|
168
231
|
}: {
|
|
169
232
|
toolbarLeft?: ReactNode
|
|
170
233
|
toolbarRight?: ReactNode
|
|
234
|
+
viewBar: boolean
|
|
171
235
|
children: ReactNode
|
|
172
236
|
overlays?: ReactNode
|
|
173
237
|
stageOverlay?: ReactNode
|
|
174
238
|
}) {
|
|
175
239
|
return (
|
|
176
|
-
<div
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
240
|
+
<div className="relative flex min-w-0 flex-1 flex-col overflow-hidden">
|
|
241
|
+
{/* The view bar row sits above the stage, one bar per pane; the host's
|
|
242
|
+
left toolbar rides after the first pane's views. */}
|
|
243
|
+
{viewBar && <ViewBarRow leading={toolbarLeft} />}
|
|
244
|
+
<div
|
|
245
|
+
className="relative flex min-h-0 flex-1 flex-col overflow-hidden"
|
|
246
|
+
style={{
|
|
247
|
+
borderTopLeftRadius: 16,
|
|
248
|
+
clipPath: 'inset(0 0 0 0 round 16px 0 0 0)',
|
|
249
|
+
boxShadow: '-4px -2px 16px rgba(0, 0, 0, 0.08), -1px 0 4px rgba(0, 0, 0, 0.04)',
|
|
250
|
+
}}
|
|
251
|
+
>
|
|
252
|
+
{((!viewBar && toolbarLeft) || toolbarRight) && (
|
|
253
|
+
<StageToolbar
|
|
254
|
+
toolbarLeft={viewBar ? undefined : toolbarLeft}
|
|
255
|
+
toolbarRight={toolbarRight}
|
|
256
|
+
/>
|
|
257
|
+
)}
|
|
258
|
+
{/* Canvas area. `isolate` matters: drei's `<Html>` computes a z-index
|
|
259
|
+
from camera distance and defaults to a range topping out at
|
|
260
|
+
16,777,271, and without a stacking context here those values compete
|
|
261
|
+
directly with the viewer toolbar (z-20), the stage overlay (z-10) and
|
|
262
|
+
the overlay band (z-30) — so an in-scene tool badge painted over all
|
|
263
|
+
three. Isolating pins every in-scene HTML layer inside the canvas,
|
|
264
|
+
where it belongs, and leaves their order relative to each other
|
|
265
|
+
untouched. */}
|
|
266
|
+
<div className="relative isolate flex-1 overflow-hidden">{children}</div>
|
|
267
|
+
{/* Stage overlay — replaces the whole stage visually (e.g. the item
|
|
268
|
+
builder) while keeping the canvas mounted. The view bar row steps
|
|
269
|
+
aside for it (see `EditorLayoutV2`); the host's toolbars stay above. */}
|
|
270
|
+
{stageOverlay && <div className="absolute inset-0 z-10">{stageOverlay}</div>}
|
|
271
|
+
{/* Overlays scoped to the stage. `data-viewer-bounds` marks the
|
|
272
|
+
draggable region the floating inspector clamps itself to. */}
|
|
273
|
+
{overlays && (
|
|
274
|
+
<div
|
|
275
|
+
className="pointer-events-none absolute inset-0 z-30"
|
|
276
|
+
data-viewer-bounds
|
|
277
|
+
style={{ transform: 'translateZ(0)' }}
|
|
278
|
+
>
|
|
279
|
+
{overlays}
|
|
280
|
+
</div>
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
215
283
|
</div>
|
|
216
284
|
)
|
|
217
285
|
}
|
|
@@ -228,6 +296,8 @@ export interface EditorLayoutV2Props {
|
|
|
228
296
|
viewerContent: ReactNode
|
|
229
297
|
overlays?: ReactNode
|
|
230
298
|
stageOverlay?: ReactNode
|
|
299
|
+
/** Show each pane's view bar. Off for hosts that present one fixed view. */
|
|
300
|
+
viewBar?: boolean
|
|
231
301
|
}
|
|
232
302
|
|
|
233
303
|
export function EditorLayoutV2({
|
|
@@ -240,6 +310,7 @@ export function EditorLayoutV2({
|
|
|
240
310
|
viewerContent,
|
|
241
311
|
overlays,
|
|
242
312
|
stageOverlay,
|
|
313
|
+
viewBar = true,
|
|
243
314
|
}: EditorLayoutV2Props) {
|
|
244
315
|
const isCaptureMode = useEditor((s) => s.isCaptureMode)
|
|
245
316
|
const isMobile = useIsMobile()
|
|
@@ -251,8 +322,9 @@ export function EditorLayoutV2({
|
|
|
251
322
|
overlays={overlays}
|
|
252
323
|
renderTabContent={renderTabContent}
|
|
253
324
|
sidebarOverlay={sidebarOverlay}
|
|
254
|
-
sidebarTabs={sidebarTabs.filter((t) => !t.noPanel)}
|
|
325
|
+
sidebarTabs={sidebarTabs.filter((t) => !t.noPanel || t.onSelect)}
|
|
255
326
|
viewerContent={viewerContent}
|
|
327
|
+
viewBar={viewBar}
|
|
256
328
|
viewerToolbarLeft={viewerToolbarLeft}
|
|
257
329
|
viewerToolbarRight={viewerToolbarRight}
|
|
258
330
|
/>
|
|
@@ -260,7 +332,7 @@ export function EditorLayoutV2({
|
|
|
260
332
|
}
|
|
261
333
|
|
|
262
334
|
return (
|
|
263
|
-
<div className="
|
|
335
|
+
<div className="flex h-full w-full flex-col bg-sidebar text-foreground">
|
|
264
336
|
{/* Top navbar */}
|
|
265
337
|
{navbarSlot}
|
|
266
338
|
|
|
@@ -278,6 +350,7 @@ export function EditorLayoutV2({
|
|
|
278
350
|
stageOverlay={stageOverlay}
|
|
279
351
|
toolbarLeft={isCaptureMode ? undefined : viewerToolbarLeft}
|
|
280
352
|
toolbarRight={isCaptureMode ? undefined : viewerToolbarRight}
|
|
353
|
+
viewBar={viewBar && !isCaptureMode && !stageOverlay}
|
|
281
354
|
>
|
|
282
355
|
{viewerContent}
|
|
283
356
|
</RightColumn>
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { emitter,
|
|
3
|
+
import { emitter, getProjectFileSink, type ProjectFileSink } from '@pascal-app/core'
|
|
4
4
|
import { disposeObject3DResources, snapLevelsToTruePositions, useViewer } from '@pascal-app/viewer'
|
|
5
5
|
import { useThree } from '@react-three/fiber'
|
|
6
6
|
import { useEffect } from 'react'
|
|
7
7
|
import * as THREE from 'three'
|
|
8
8
|
import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js'
|
|
9
9
|
import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js'
|
|
10
|
-
import {
|
|
10
|
+
import { downloadProjectFile } from '../../lib/download-project-file'
|
|
11
|
+
import {
|
|
12
|
+
exportSceneToGlb,
|
|
13
|
+
prepareSceneForExport,
|
|
14
|
+
waitForExportGeometry,
|
|
15
|
+
} from '../../lib/glb-export'
|
|
16
|
+
import { exportPreparedSceneToIfc, ifcFileName } from '../../lib/ifc-export'
|
|
11
17
|
import { exportSceneLevelsForPrint } from '../../lib/level-print-export'
|
|
12
18
|
import type { ModelExport, ModelExportArtifact } from '../../lib/model-export'
|
|
13
19
|
import {
|
|
@@ -20,6 +26,7 @@ import { filterPreparedSceneForPrintContent } from '../../lib/print-content-scop
|
|
|
20
26
|
import { exportSceneToPrintStl, mergePrintExportDiagnostics } from '../../lib/print-export'
|
|
21
27
|
import { applySemanticPrintFeatureThickness } from '../../lib/print-feature-thickness'
|
|
22
28
|
import { compileSemanticPrintShellWithManifold } from '../../lib/print-shell-compiler-manifold-worker'
|
|
29
|
+
import { getSavedSceneDocument } from '../../lib/scene'
|
|
23
30
|
import { exportSceneToUsdz } from '../../lib/usdz-export'
|
|
24
31
|
import useEditor from '../../store/use-editor'
|
|
25
32
|
|
|
@@ -51,7 +58,11 @@ export function ExportManager() {
|
|
|
51
58
|
const setModelExport = useEditor((state) => state.setModelExport)
|
|
52
59
|
|
|
53
60
|
useEffect(() => {
|
|
54
|
-
const exportFn: ModelExport = async (format = 'glb',
|
|
61
|
+
const exportFn: ModelExport = async (format = 'glb', requested = {}) => {
|
|
62
|
+
const finishArtifact = artifactFinisher(getProjectFileSink())
|
|
63
|
+
// Resolve once: scene preparation prunes hidden nodes by default, and the
|
|
64
|
+
// IFC writer must drop the same nodes it rebuilds parametrically.
|
|
65
|
+
const options = { ...requested, onlyVisible: requested.onlyVisible ?? true }
|
|
55
66
|
// Find the scene renderer group by name
|
|
56
67
|
const sceneGroup = scene.getObjectByName('scene-renderer')
|
|
57
68
|
if (!sceneGroup) {
|
|
@@ -67,11 +78,12 @@ export function ExportManager() {
|
|
|
67
78
|
// without it every plant exports as its raycast collider, a white box).
|
|
68
79
|
useViewer.getState().setExporting(true)
|
|
69
80
|
try {
|
|
70
|
-
await
|
|
81
|
+
await waitForExportGeometry(getSavedSceneDocument().nodes, options)
|
|
82
|
+
const { nodes, collections } = getSavedSceneDocument()
|
|
71
83
|
|
|
72
84
|
if (format === 'glb') {
|
|
73
85
|
const warnings: string[] = []
|
|
74
|
-
const buffer = await exportSceneToGlb(sceneGroup,
|
|
86
|
+
const buffer = await exportSceneToGlb(sceneGroup, nodes, {
|
|
75
87
|
...options,
|
|
76
88
|
onWarning: (warning) => warnings.push(warning),
|
|
77
89
|
})
|
|
@@ -81,7 +93,7 @@ export function ExportManager() {
|
|
|
81
93
|
|
|
82
94
|
if (format === 'usdz') {
|
|
83
95
|
const warnings: string[] = []
|
|
84
|
-
const data = await exportSceneToUsdz(sceneGroup,
|
|
96
|
+
const data = await exportSceneToUsdz(sceneGroup, nodes, {
|
|
85
97
|
...options,
|
|
86
98
|
onWarning: (warning) => warnings.push(warning),
|
|
87
99
|
})
|
|
@@ -95,12 +107,11 @@ export function ExportManager() {
|
|
|
95
107
|
// window, so the export snapshots the clean building, then restore.
|
|
96
108
|
emitter.emit('thumbnail:before-capture', undefined)
|
|
97
109
|
const restoreLevels = snapLevelsToTruePositions()
|
|
98
|
-
const nodes = useScene.getState().nodes
|
|
99
110
|
let prepared: ReturnType<typeof prepareSceneForExport>
|
|
100
111
|
try {
|
|
101
112
|
prepared = prepareSceneForExport(sceneGroup, nodes, {
|
|
102
113
|
...options,
|
|
103
|
-
requireSynchronousBake: format === 'stl' || format === 'obj',
|
|
114
|
+
requireSynchronousBake: format === 'stl' || format === 'obj' || format === 'ifc',
|
|
104
115
|
})
|
|
105
116
|
} finally {
|
|
106
117
|
restoreLevels()
|
|
@@ -206,6 +217,23 @@ export function ExportManager() {
|
|
|
206
217
|
return finishArtifact(blob, `model_${date}.stl`, options.download)
|
|
207
218
|
}
|
|
208
219
|
|
|
220
|
+
if (format === 'ifc') {
|
|
221
|
+
const { data, warnings } = exportPreparedSceneToIfc(exportScene, nodes, {
|
|
222
|
+
collections,
|
|
223
|
+
projectName: options.projectName,
|
|
224
|
+
onlyVisible: options.onlyVisible,
|
|
225
|
+
excludedNodeTypes: options.excludedNodeTypes,
|
|
226
|
+
})
|
|
227
|
+
const blob = new Blob([data], { type: 'application/x-step' })
|
|
228
|
+
return finishArtifact(
|
|
229
|
+
blob,
|
|
230
|
+
ifcFileName(options.projectName, `model_${date}`),
|
|
231
|
+
options.download,
|
|
232
|
+
undefined,
|
|
233
|
+
warnings,
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
209
237
|
if (format === 'obj') {
|
|
210
238
|
const exporter = new OBJExporter()
|
|
211
239
|
const result = exporter.parse(exportScene)
|
|
@@ -236,22 +264,15 @@ export function ExportManager() {
|
|
|
236
264
|
return null
|
|
237
265
|
}
|
|
238
266
|
|
|
239
|
-
function
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function downloadBlob(blob: Blob, filename: string) {
|
|
251
|
-
const url = URL.createObjectURL(blob)
|
|
252
|
-
const link = document.createElement('a')
|
|
253
|
-
link.href = url
|
|
254
|
-
link.download = filename
|
|
255
|
-
link.click()
|
|
256
|
-
URL.revokeObjectURL(url)
|
|
267
|
+
function artifactFinisher(sink: ProjectFileSink | null) {
|
|
268
|
+
return async (
|
|
269
|
+
blob: Blob,
|
|
270
|
+
filename: string,
|
|
271
|
+
download: boolean | undefined,
|
|
272
|
+
metadata?: unknown,
|
|
273
|
+
warnings?: readonly string[],
|
|
274
|
+
): Promise<ModelExportArtifact> => {
|
|
275
|
+
if (download !== false) await downloadProjectFile(blob, filename, sink)
|
|
276
|
+
return { blob, filename, metadata, warnings: warnings?.length ? warnings : undefined }
|
|
277
|
+
}
|
|
257
278
|
}
|