@selvajs/ui 6.6.0-beta.9 → 7.0.1-beta.0
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 +0 -3
- package/dist/components/ErrorScreen.svelte +1 -1
- package/dist/components/compute/AppLayout.svelte +230 -85
- package/dist/components/compute/AppLayout.svelte.d.ts +14 -2
- package/dist/components/compute/CollapsedPanelStrip.svelte +4 -2
- package/dist/components/compute/ComputeApp.svelte +6 -2
- package/dist/components/compute/ComputeApp.svelte.d.ts +1 -1
- package/dist/components/compute/ComputeMessagesDialog.svelte +3 -3
- package/dist/components/compute/ParameterPresetManager.svelte +1 -1
- package/dist/components/compute/SolveMessages.svelte +79 -88
- package/dist/components/compute/SolveMessages.svelte.d.ts +5 -0
- package/dist/components/layout/AppShell.svelte +2 -2
- package/dist/components/layout/FooterItemRenderer.svelte +2 -2
- package/dist/components/layout/FooterItemRenderer.svelte.d.ts +1 -1
- package/dist/components/layout/PageContent.svelte +3 -2
- package/dist/components/layout/PageFooter.svelte +9 -6
- package/dist/components/layout/PageHeader.svelte +3 -3
- package/dist/components/layout/SideNav.svelte +3 -3
- package/dist/components/layout/SubNav.svelte +2 -2
- package/dist/components/preview/ChartOutput.svelte +141 -50
- package/dist/components/preview/Group.svelte +9 -9
- package/dist/components/preview/HelpButton.svelte +1 -1
- package/dist/components/preview/ImageOutput.svelte +13 -10
- package/dist/components/preview/InputControl.svelte +13 -12
- package/dist/components/preview/OutputDisplay.svelte +26 -17
- package/dist/components/preview/TabBar.svelte +8 -6
- package/dist/components/preview/TabBar.svelte.d.ts +2 -0
- package/dist/components/preview/TabContent.svelte +8 -8
- package/dist/components/preview/TabLayout.svelte +6 -7
- package/dist/components/preview/inputs/CheckboxInput.svelte +1 -1
- package/dist/components/preview/inputs/ChecklistInput.svelte +5 -5
- package/dist/components/preview/inputs/ColorInput.svelte +356 -14
- package/dist/components/preview/inputs/ColorInput.svelte.d.ts +1 -0
- package/dist/components/preview/inputs/DropdownInput.svelte +3 -3
- package/dist/components/preview/inputs/FileInput.svelte +17 -12
- package/dist/components/preview/inputs/GeometryInput.svelte +4 -4
- package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +1 -1
- package/dist/components/preview/inputs/NumberInput.svelte +8 -8
- package/dist/components/preview/inputs/OptionGlyph.svelte +1 -1
- package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +1 -1
- package/dist/components/preview/inputs/SegmentedInput.svelte +3 -2
- package/dist/components/preview/inputs/TextInput.svelte +5 -5
- package/dist/components/preview/inputs/TileInput.svelte +8 -5
- package/dist/components/primitives/CalculateButton.svelte +10 -4
- package/dist/components/primitives/Callout.svelte +8 -6
- package/dist/components/primitives/Callout.svelte.d.ts +4 -4
- package/dist/components/primitives/DataTable.svelte +1 -1
- package/dist/components/primitives/FilterableDropdown.svelte +13 -1
- package/dist/components/primitives/FilterableDropdown.svelte.d.ts +5 -0
- package/dist/components/primitives/ImageUploadField.svelte +1 -1
- package/dist/components/primitives/SolvingIndicator.svelte +242 -41
- package/dist/components/primitives/SolvingIndicator.svelte.d.ts +13 -5
- package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/components/primitives/badge/badge.svelte +2 -2
- package/dist/components/primitives/badge/badge.svelte.d.ts +6 -6
- package/dist/components/primitives/button/button.svelte +7 -8
- package/dist/components/primitives/button/button.svelte.d.ts +19 -19
- package/dist/components/primitives/card/card.svelte +1 -1
- package/dist/components/primitives/card/card.svelte.d.ts +1 -1
- package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
- package/dist/components/primitives/command/command-input.svelte +1 -1
- package/dist/components/primitives/command/command-item.svelte +1 -1
- package/dist/components/primitives/command/command-link-item.svelte +1 -1
- package/dist/components/primitives/command/command.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-checkbox-item.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-item.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-radio-item.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
- package/dist/components/primitives/context-menu/context-menu-sub-trigger.svelte +1 -1
- package/dist/components/primitives/dialog/dialog-content.svelte +3 -3
- package/dist/components/primitives/drawer/Drawer.svelte +1 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +31 -11
- package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +2 -0
- package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +5 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +2 -0
- package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +4 -2
- package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +2 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
- package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
- package/dist/components/primitives/index.d.ts +1 -1
- package/dist/components/primitives/index.js +1 -1
- package/dist/components/primitives/input/input.svelte +2 -2
- package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +1 -1
- package/dist/components/primitives/input-group/input-group.svelte +1 -1
- package/dist/components/primitives/mode-toggle/mode-toggle.svelte +2 -2
- package/dist/components/primitives/popover/popover-content.svelte +1 -1
- package/dist/components/primitives/resizable/resizable-handle.svelte +2 -2
- package/dist/components/primitives/search/search.svelte +1 -1
- package/dist/components/primitives/select/select-content.svelte +1 -1
- package/dist/components/primitives/select/select-item.svelte +1 -1
- package/dist/components/primitives/select/select-trigger.svelte +1 -1
- package/dist/components/primitives/slider/slider.svelte +1 -1
- package/dist/components/primitives/switch/switch.svelte +1 -1
- package/dist/components/primitives/tabs/tabs-list.svelte +2 -2
- package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +6 -6
- package/dist/components/primitives/tabs/tabs-trigger.svelte +2 -2
- package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +6 -6
- package/dist/components/primitives/textarea/textarea.svelte +1 -1
- package/dist/components/primitives/toggle/toggle.svelte +8 -2
- package/dist/components/primitives/toggle/toggle.svelte.d.ts +10 -4
- package/dist/components/primitives/toggle-group/toggle-group-item.svelte +1 -1
- package/dist/components/primitives/toggle-group/toggle-group.svelte +1 -1
- package/dist/components/primitives/tooltip/index.d.ts +6 -0
- package/dist/components/primitives/tooltip/index.js +8 -0
- package/dist/components/primitives/tooltip/tooltip-content.svelte +34 -0
- package/dist/components/primitives/tooltip/tooltip-content.svelte.d.ts +10 -0
- package/dist/components/primitives/tooltip/tooltip-portal.svelte +7 -0
- package/dist/components/primitives/tooltip/tooltip-portal.svelte.d.ts +4 -0
- package/dist/components/primitives/tooltip/tooltip-provider.svelte +7 -0
- package/dist/components/primitives/tooltip/tooltip-provider.svelte.d.ts +4 -0
- package/dist/components/primitives/tooltip/tooltip-trigger.svelte +7 -0
- package/dist/components/primitives/tooltip/tooltip-trigger.svelte.d.ts +4 -0
- package/dist/components/primitives/tooltip/tooltip.svelte +7 -0
- package/dist/components/primitives/tooltip/tooltip.svelte.d.ts +4 -0
- package/dist/components/viewer/MeshMetadataPanel.svelte +2 -2
- package/dist/components/viewer/SceneManager.svelte +32 -21
- package/dist/components/viewer/SceneManager.svelte.d.ts +3 -1
- package/dist/components/viewer/Viewer.svelte +128 -178
- package/dist/components/viewer/Viewer.svelte.d.ts +7 -2
- package/dist/components/viewer/ViewerDock.svelte +452 -0
- package/dist/components/viewer/ViewerDock.svelte.d.ts +42 -0
- package/dist/composables/useFooterItem.svelte.d.ts +1 -1
- package/dist/composables/useFooterItem.svelte.js +1 -1
- package/dist/compute/liveProgress.svelte.d.ts +16 -0
- package/dist/compute/liveProgress.svelte.js +90 -0
- package/dist/compute/solving.svelte.d.ts +7 -9
- package/dist/compute/solving.svelte.js +56 -48
- package/dist/constants.d.ts +6 -8
- package/dist/constants.js +8 -11
- package/dist/contexts/hostContext.svelte.d.ts +1 -1
- package/dist/features/chart/plotly-compat.d.ts +15 -0
- package/dist/features/chart/plotly-compat.js +124 -0
- package/dist/i18n/messages.d.ts +17 -0
- package/dist/i18n/messages.js +26 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/public.d.ts +1 -0
- package/dist/public.js +1 -0
- package/dist/schema/visibility-rules.d.ts +7 -1
- package/dist/schema/visibility-rules.js +17 -0
- package/dist/styles/base.css +100 -86
- package/dist/utils/color-space.d.ts +21 -0
- package/dist/utils/color-space.js +90 -0
- package/package.json +31 -23
- package/src/lib/components/ErrorScreen.svelte +1 -1
- package/src/lib/components/compute/AppLayout.svelte +231 -86
- package/src/lib/components/compute/CollapsedPanelStrip.svelte +4 -2
- package/src/lib/components/compute/ComputeApp.svelte +6 -2
- package/src/lib/components/compute/ComputeMessagesDialog.svelte +4 -4
- package/src/lib/components/compute/ParameterPresetManager.svelte +1 -1
- package/src/lib/components/compute/SolveMessages.svelte +81 -90
- package/src/lib/components/layout/AppShell.svelte +2 -2
- package/src/lib/components/layout/FooterItemRenderer.svelte +2 -2
- package/src/lib/components/layout/PageContent.svelte +3 -2
- package/src/lib/components/layout/PageFooter.svelte +9 -6
- package/src/lib/components/layout/PageHeader.svelte +3 -3
- package/src/lib/components/layout/SideNav.svelte +4 -4
- package/src/lib/components/layout/SubNav.svelte +2 -2
- package/src/lib/components/preview/ChartOutput.svelte +141 -50
- package/src/lib/components/preview/Group.svelte +9 -9
- package/src/lib/components/preview/HelpButton.svelte +1 -1
- package/src/lib/components/preview/ImageOutput.svelte +13 -10
- package/src/lib/components/preview/InputControl.svelte +13 -12
- package/src/lib/components/preview/OutputDisplay.svelte +26 -17
- package/src/lib/components/preview/TabBar.svelte +8 -6
- package/src/lib/components/preview/TabContent.svelte +8 -8
- package/src/lib/components/preview/TabLayout.svelte +6 -7
- package/src/lib/components/preview/inputs/CheckboxInput.svelte +1 -1
- package/src/lib/components/preview/inputs/ChecklistInput.svelte +5 -5
- package/src/lib/components/preview/inputs/ColorInput.svelte +356 -14
- package/src/lib/components/preview/inputs/DropdownInput.svelte +3 -3
- package/src/lib/components/preview/inputs/FileInput.svelte +17 -12
- package/src/lib/components/preview/inputs/GeometryInput.svelte +4 -4
- package/src/lib/components/preview/inputs/NumberInput.svelte +8 -8
- package/src/lib/components/preview/inputs/OptionGlyph.svelte +2 -2
- package/src/lib/components/preview/inputs/SegmentedInput.svelte +3 -2
- package/src/lib/components/preview/inputs/TextInput.svelte +5 -5
- package/src/lib/components/preview/inputs/TileInput.svelte +8 -5
- package/src/lib/components/primitives/CalculateButton.svelte +10 -4
- package/src/lib/components/primitives/Callout.svelte +9 -7
- package/src/lib/components/primitives/DataTable.svelte +1 -1
- package/src/lib/components/primitives/FilterableDropdown.svelte +14 -2
- package/src/lib/components/primitives/ImageUploadField.svelte +1 -1
- package/src/lib/components/primitives/IssueList.svelte +1 -1
- package/src/lib/components/primitives/SeverityIcon.svelte +1 -1
- package/src/lib/components/primitives/SolvingIndicator.svelte +242 -41
- package/src/lib/components/primitives/StateDisplay.svelte +1 -1
- package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +2 -2
- package/src/lib/components/primitives/alert-dialog/alert-dialog-cancel.svelte +2 -2
- package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +2 -2
- package/src/lib/components/primitives/alert-dialog/alert-dialog-description.svelte +1 -1
- package/src/lib/components/primitives/alert-dialog/alert-dialog-footer.svelte +1 -1
- package/src/lib/components/primitives/alert-dialog/alert-dialog-header.svelte +1 -1
- package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
- package/src/lib/components/primitives/alert-dialog/alert-dialog-title.svelte +1 -1
- package/src/lib/components/primitives/badge/badge.svelte +3 -3
- package/src/lib/components/primitives/button/button.svelte +7 -8
- package/src/lib/components/primitives/button-group/button-group-separator.svelte +2 -2
- package/src/lib/components/primitives/button-group/button-group-text.svelte +1 -1
- package/src/lib/components/primitives/button-group/button-group.svelte +1 -1
- package/src/lib/components/primitives/card/card-content.svelte +1 -1
- package/src/lib/components/primitives/card/card-description.svelte +1 -1
- package/src/lib/components/primitives/card/card-footer.svelte +1 -1
- package/src/lib/components/primitives/card/card-header.svelte +1 -1
- package/src/lib/components/primitives/card/card-title.svelte +1 -1
- package/src/lib/components/primitives/card/card.svelte +2 -2
- package/src/lib/components/primitives/checkbox/checkbox.svelte +2 -2
- package/src/lib/components/primitives/command/command-dialog.svelte +2 -2
- package/src/lib/components/primitives/command/command-empty.svelte +1 -1
- package/src/lib/components/primitives/command/command-group.svelte +1 -1
- package/src/lib/components/primitives/command/command-input.svelte +3 -3
- package/src/lib/components/primitives/command/command-item.svelte +2 -2
- package/src/lib/components/primitives/command/command-link-item.svelte +2 -2
- package/src/lib/components/primitives/command/command-list.svelte +1 -1
- package/src/lib/components/primitives/command/command-separator.svelte +1 -1
- package/src/lib/components/primitives/command/command-shortcut.svelte +1 -1
- package/src/lib/components/primitives/command/command.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-checkbox-item.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-content.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-group-heading.svelte +1 -1
- package/src/lib/components/primitives/context-menu/context-menu-item.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-label.svelte +1 -1
- package/src/lib/components/primitives/context-menu/context-menu-radio-item.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-separator.svelte +1 -1
- package/src/lib/components/primitives/context-menu/context-menu-shortcut.svelte +1 -1
- package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +2 -2
- package/src/lib/components/primitives/context-menu/context-menu-sub-trigger.svelte +2 -2
- package/src/lib/components/primitives/dialog/dialog-content.svelte +4 -4
- package/src/lib/components/primitives/dialog/dialog-description.svelte +1 -1
- package/src/lib/components/primitives/dialog/dialog-footer.svelte +1 -1
- package/src/lib/components/primitives/dialog/dialog-header.svelte +1 -1
- package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
- package/src/lib/components/primitives/dialog/dialog-title.svelte +1 -1
- package/src/lib/components/primitives/drawer/Drawer.svelte +1 -1
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +32 -12
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +6 -2
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +5 -3
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +1 -1
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +2 -2
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +1 -1
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +2 -2
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +2 -2
- package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -2
- package/src/lib/components/primitives/empty/empty-content.svelte +1 -1
- package/src/lib/components/primitives/empty/empty-description.svelte +1 -1
- package/src/lib/components/primitives/empty/empty-header.svelte +1 -1
- package/src/lib/components/primitives/empty/empty-media.svelte +1 -1
- package/src/lib/components/primitives/empty/empty-title.svelte +1 -1
- package/src/lib/components/primitives/empty/empty.svelte +1 -1
- package/src/lib/components/primitives/field/field-content.svelte +1 -1
- package/src/lib/components/primitives/field/field-description.svelte +1 -1
- package/src/lib/components/primitives/field/field-error.svelte +1 -1
- package/src/lib/components/primitives/field/field-group.svelte +1 -1
- package/src/lib/components/primitives/field/field-label.svelte +2 -2
- package/src/lib/components/primitives/field/field-legend.svelte +1 -1
- package/src/lib/components/primitives/field/field-separator.svelte +2 -2
- package/src/lib/components/primitives/field/field-set.svelte +1 -1
- package/src/lib/components/primitives/field/field-title.svelte +1 -1
- package/src/lib/components/primitives/field/field.svelte +1 -1
- package/src/lib/components/primitives/index.ts +1 -1
- package/src/lib/components/primitives/input/input.svelte +3 -3
- package/src/lib/components/primitives/input-group/input-group-addon.svelte +1 -1
- package/src/lib/components/primitives/input-group/input-group-button.svelte +2 -2
- package/src/lib/components/primitives/input-group/input-group-input.svelte +2 -2
- package/src/lib/components/primitives/input-group/input-group-text.svelte +1 -1
- package/src/lib/components/primitives/input-group/input-group-textarea.svelte +2 -2
- package/src/lib/components/primitives/input-group/input-group.svelte +2 -2
- package/src/lib/components/primitives/label/label.svelte +1 -1
- package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +2 -2
- package/src/lib/components/primitives/popover/popover-content.svelte +2 -2
- package/src/lib/components/primitives/popover/popover-description.svelte +1 -1
- package/src/lib/components/primitives/popover/popover-header.svelte +1 -1
- package/src/lib/components/primitives/popover/popover-title.svelte +1 -1
- package/src/lib/components/primitives/popover/popover-trigger.svelte +1 -1
- package/src/lib/components/primitives/resizable/resizable-handle.svelte +3 -3
- package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -1
- package/src/lib/components/primitives/scroll-area/scroll-area-scrollbar.svelte +1 -1
- package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
- package/src/lib/components/primitives/search/search.svelte +2 -2
- package/src/lib/components/primitives/select/select-content.svelte +2 -2
- package/src/lib/components/primitives/select/select-group-heading.svelte +1 -1
- package/src/lib/components/primitives/select/select-item.svelte +2 -2
- package/src/lib/components/primitives/select/select-label.svelte +1 -1
- package/src/lib/components/primitives/select/select-scroll-down-button.svelte +1 -1
- package/src/lib/components/primitives/select/select-scroll-up-button.svelte +1 -1
- package/src/lib/components/primitives/select/select-separator.svelte +2 -2
- package/src/lib/components/primitives/select/select-trigger.svelte +2 -2
- package/src/lib/components/primitives/separator/separator.svelte +1 -1
- package/src/lib/components/primitives/slider/slider.svelte +2 -2
- package/src/lib/components/primitives/spinner/spinner.svelte +1 -1
- package/src/lib/components/primitives/switch/switch.svelte +2 -2
- package/src/lib/components/primitives/tabs/tabs-content.svelte +1 -1
- package/src/lib/components/primitives/tabs/tabs-list.svelte +3 -3
- package/src/lib/components/primitives/tabs/tabs-trigger.svelte +3 -3
- package/src/lib/components/primitives/tabs/tabs.svelte +1 -1
- package/src/lib/components/primitives/textarea/textarea.svelte +2 -2
- package/src/lib/components/primitives/toggle/toggle.svelte +9 -3
- package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +3 -3
- package/src/lib/components/primitives/toggle-group/toggle-group.svelte +3 -3
- package/src/lib/components/primitives/tooltip/index.ts +19 -0
- package/src/lib/components/primitives/tooltip/tooltip-content.svelte +34 -0
- package/src/lib/components/primitives/tooltip/tooltip-portal.svelte +7 -0
- package/src/lib/components/primitives/tooltip/tooltip-provider.svelte +7 -0
- package/src/lib/components/primitives/tooltip/tooltip-trigger.svelte +7 -0
- package/src/lib/components/primitives/tooltip/tooltip.svelte +7 -0
- package/src/lib/components/viewer/MeshMetadataPanel.svelte +2 -2
- package/src/lib/components/viewer/SceneManager.svelte +32 -21
- package/src/lib/components/viewer/Viewer.svelte +129 -179
- package/src/lib/components/viewer/ViewerDock.svelte +452 -0
- package/src/lib/composables/useFooterItem.svelte.ts +1 -1
- package/src/lib/compute/liveProgress.svelte.ts +103 -0
- package/src/lib/compute/solving.svelte.ts +56 -55
- package/src/lib/constants.ts +8 -11
- package/src/lib/contexts/hostContext.svelte.ts +1 -1
- package/src/lib/features/chart/plotly-compat.ts +141 -0
- package/src/lib/i18n/messages.ts +43 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/public.ts +1 -0
- package/src/lib/schema/visibility-rules.ts +27 -1
- package/src/lib/styles/base.css +100 -86
- package/src/lib/utils/color-space.ts +107 -0
- package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +0 -39
- package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte.d.ts +0 -3
- package/dist/components/primitives/theme-switcher/index.d.ts +0 -1
- package/dist/components/primitives/theme-switcher/index.js +0 -1
- package/dist/styles/themes/cyberpunk.css +0 -98
- package/dist/styles/themes/neutral.css +0 -72
- package/dist/styles/themes/ocean.css +0 -75
- package/dist/styles/themes/selva.css +0 -105
- package/dist/theme/themeStore.svelte.d.ts +0 -12
- package/dist/theme/themeStore.svelte.js +0 -40
- package/dist/theme/themes.d.ts +0 -5
- package/dist/theme/themes.js +0 -13
- package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +0 -39
- package/src/lib/components/primitives/theme-switcher/index.ts +0 -1
- package/src/lib/styles/themes/cyberpunk.css +0 -98
- package/src/lib/styles/themes/neutral.css +0 -72
- package/src/lib/styles/themes/ocean.css +0 -75
- package/src/lib/styles/themes/selva.css +0 -105
- package/src/lib/theme/themeStore.svelte.ts +0 -50
- package/src/lib/theme/themes.ts +0 -18
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MediaQuery } from 'svelte/reactivity';
|
|
3
|
+
import {
|
|
4
|
+
Camera,
|
|
5
|
+
Grid3x3,
|
|
6
|
+
Layers,
|
|
7
|
+
LocateFixed,
|
|
8
|
+
Maximize,
|
|
9
|
+
Minimize,
|
|
10
|
+
Moon,
|
|
11
|
+
Ellipsis,
|
|
12
|
+
Palette,
|
|
13
|
+
Ruler,
|
|
14
|
+
Settings2,
|
|
15
|
+
Spline,
|
|
16
|
+
Cuboid
|
|
17
|
+
} from '@lucide/svelte';
|
|
18
|
+
import type { CameraProjection, Look, ViewPreset } from '@selvajs/visualization/render';
|
|
19
|
+
import * as DropdownMenu from '../primitives/dropdown-menu/index.js';
|
|
20
|
+
import type { ViewerMessages } from '../../i18n/messages.js';
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
t: ViewerMessages;
|
|
24
|
+
/** Fades the dock out while a host drawer covers the viewer. */
|
|
25
|
+
hidden?: boolean;
|
|
26
|
+
showDisplay: boolean;
|
|
27
|
+
showGrid: boolean;
|
|
28
|
+
showSceneManager: boolean;
|
|
29
|
+
showScreenshot: boolean;
|
|
30
|
+
showFullscreen: boolean;
|
|
31
|
+
styleOptions: { look: Look; label: string }[];
|
|
32
|
+
viewPresets: { preset: ViewPreset; label: string }[];
|
|
33
|
+
renderStyle: Look;
|
|
34
|
+
nightOn: boolean;
|
|
35
|
+
edgesVisible: boolean;
|
|
36
|
+
measureActive: boolean;
|
|
37
|
+
gridVisible: boolean;
|
|
38
|
+
sceneManagerOpen: boolean;
|
|
39
|
+
projection: CameraProjection;
|
|
40
|
+
isFullscreen: boolean;
|
|
41
|
+
onSetLook: (look: Look) => void;
|
|
42
|
+
onToggleNight: () => void;
|
|
43
|
+
onToggleEdges: () => void;
|
|
44
|
+
onToggleMeasure: () => void;
|
|
45
|
+
onToggleGrid: () => void;
|
|
46
|
+
onToggleSceneManager: () => void;
|
|
47
|
+
onToggleProjection: () => void;
|
|
48
|
+
onSetView: (preset: ViewPreset) => void;
|
|
49
|
+
onFit: () => void;
|
|
50
|
+
onScreenshot: () => void;
|
|
51
|
+
onToggleFullscreen: () => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let {
|
|
55
|
+
t,
|
|
56
|
+
hidden = false,
|
|
57
|
+
showDisplay,
|
|
58
|
+
showGrid,
|
|
59
|
+
showSceneManager,
|
|
60
|
+
showScreenshot,
|
|
61
|
+
showFullscreen,
|
|
62
|
+
styleOptions,
|
|
63
|
+
viewPresets,
|
|
64
|
+
renderStyle,
|
|
65
|
+
nightOn,
|
|
66
|
+
edgesVisible,
|
|
67
|
+
measureActive,
|
|
68
|
+
gridVisible,
|
|
69
|
+
sceneManagerOpen,
|
|
70
|
+
projection,
|
|
71
|
+
isFullscreen,
|
|
72
|
+
onSetLook,
|
|
73
|
+
onToggleNight,
|
|
74
|
+
onToggleEdges,
|
|
75
|
+
onToggleMeasure,
|
|
76
|
+
onToggleGrid,
|
|
77
|
+
onToggleSceneManager,
|
|
78
|
+
onToggleProjection,
|
|
79
|
+
onSetView,
|
|
80
|
+
onFit,
|
|
81
|
+
onScreenshot,
|
|
82
|
+
onToggleFullscreen
|
|
83
|
+
}: Props = $props();
|
|
84
|
+
|
|
85
|
+
// A hairline pill at the bottom edge is the iOS home indicator on a phone, and swiping it leaves
|
|
86
|
+
// the app. Touch gets a visible round button instead.
|
|
87
|
+
const touch = new MediaQuery('(pointer: coarse)');
|
|
88
|
+
const reducedMotion = new MediaQuery('(prefers-reduced-motion: reduce)');
|
|
89
|
+
|
|
90
|
+
const COLLAPSED = $derived(touch.current ? { w: 44, h: 44 } : { w: 56, h: 5 });
|
|
91
|
+
const EXPANDED_H = $derived(touch.current ? 54 : 42);
|
|
92
|
+
const PAD = 4;
|
|
93
|
+
|
|
94
|
+
let dockEl: HTMLDivElement | undefined = $state();
|
|
95
|
+
let rowWidth = $state(0);
|
|
96
|
+
let engaged = $state(false);
|
|
97
|
+
// Set by an outside press: the dock was dismissed, so it shrinks faster.
|
|
98
|
+
let dismissed = $state(false);
|
|
99
|
+
let menusOpen = $state(0);
|
|
100
|
+
let focusWithin = $state(false);
|
|
101
|
+
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
102
|
+
|
|
103
|
+
const wantOpen = $derived(engaged || menusOpen > 0 || focusWithin);
|
|
104
|
+
|
|
105
|
+
// Opening leads: the pill grows first and the buttons pop in behind it. Closing mirrors it: the
|
|
106
|
+
// buttons fade first, then the pill shrinks. Without the delay on close the row is clipped mid-fade.
|
|
107
|
+
const EASE = 'cubic-bezier(0.32, 0.72, 0, 1)';
|
|
108
|
+
const bottom = $derived(touch.current ? 'max(1rem,env(safe-area-inset-bottom))' : '0.75rem');
|
|
109
|
+
const containerStyle = $derived.by(() => {
|
|
110
|
+
const geometry = wantOpen
|
|
111
|
+
? `width:${rowWidth + PAD * 2 + 2}px;height:${EXPANDED_H}px;border-radius:12px;padding:${PAD}px`
|
|
112
|
+
: `width:${COLLAPSED.w}px;height:${COLLAPSED.h}px;border-radius:${touch.current ? 22 : 99}px;padding:0px`;
|
|
113
|
+
const size = `bottom:${bottom};${geometry}`;
|
|
114
|
+
if (reducedMotion.current) return size;
|
|
115
|
+
const ms = wantOpen ? 420 : dismissed ? 130 : 170;
|
|
116
|
+
const delay = wantOpen || dismissed ? 0 : 20;
|
|
117
|
+
const props = ['width', 'height', 'border-radius', 'padding'];
|
|
118
|
+
return `${size};transition:${props.map((p) => `${p} ${ms}ms ${EASE} ${delay}ms`).join(',')},opacity 200ms ease`;
|
|
119
|
+
});
|
|
120
|
+
const itemStyle = (index: number) => {
|
|
121
|
+
if (reducedMotion.current) return `opacity:${wantOpen ? 1 : 0}`;
|
|
122
|
+
const delay = 110 + index * 35;
|
|
123
|
+
return wantOpen
|
|
124
|
+
? `opacity:1;transform:none;transition:opacity 240ms ease ${delay}ms,transform 420ms cubic-bezier(0.34,1.45,0.5,1) ${delay}ms`
|
|
125
|
+
: 'opacity:0;transform:translateY(6px) scale(0.85);transition:opacity 100ms ease,transform 100ms ease';
|
|
126
|
+
};
|
|
127
|
+
// The touch button's settings glyph hands over to the row.
|
|
128
|
+
const glyphStyle = $derived(
|
|
129
|
+
`opacity:${touch.current && !wantOpen ? 1 : 0};${reducedMotion.current ? '' : `transition:opacity ${wantOpen ? 100 : 100}ms ease ${wantOpen || dismissed ? 0 : 60}ms`}`
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Touch has no hover to reopen it, so there the dock stays open until a press lands outside it.
|
|
133
|
+
function scheduleCollapse(delay = 150) {
|
|
134
|
+
clearTimeout(idleTimer);
|
|
135
|
+
idleTimer = setTimeout(() => (engaged = false), delay);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function engage() {
|
|
139
|
+
engaged = true;
|
|
140
|
+
dismissed = false;
|
|
141
|
+
clearTimeout(idleTimer);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function handlePointerMove(event: PointerEvent) {
|
|
145
|
+
if (!dockEl || touch.current || event.pointerType === 'touch') return;
|
|
146
|
+
// Orbiting or box-dragging with the button down should never pop the dock open.
|
|
147
|
+
if (event.buttons) return;
|
|
148
|
+
const host = dockEl.offsetParent;
|
|
149
|
+
if (!host || !(event.target instanceof Node) || !host.contains(event.target)) {
|
|
150
|
+
if (engaged) scheduleCollapse();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const r = dockEl.getBoundingClientRect();
|
|
154
|
+
const near =
|
|
155
|
+
event.clientY > r.top - 36 && Math.abs(event.clientX - (r.left + r.width / 2)) < 110;
|
|
156
|
+
if (near) engage();
|
|
157
|
+
else if (engaged) scheduleCollapse();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function handleWindowPointerDown(event: PointerEvent) {
|
|
161
|
+
if (!engaged || !dockEl || !(event.target instanceof Node)) return;
|
|
162
|
+
if (!dockEl.contains(event.target)) {
|
|
163
|
+
clearTimeout(idleTimer);
|
|
164
|
+
dismissed = true;
|
|
165
|
+
engaged = false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function openFromCollapsed() {
|
|
170
|
+
if (wantOpen) return;
|
|
171
|
+
engage();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ==========================================================================
|
|
175
|
+
// Long-press labels
|
|
176
|
+
// ==========================================================================
|
|
177
|
+
|
|
178
|
+
// The icons carry no text and touch has no tooltip, so holding a button names it instead of
|
|
179
|
+
// pressing it.
|
|
180
|
+
const LONG_PRESS_MS = 450;
|
|
181
|
+
const HINT_LINGER_MS = 1200;
|
|
182
|
+
let hint = $state<string | null>(null);
|
|
183
|
+
let pressTimer: ReturnType<typeof setTimeout> | undefined;
|
|
184
|
+
let hintTimer: ReturnType<typeof setTimeout> | undefined;
|
|
185
|
+
let swallowClick = false;
|
|
186
|
+
|
|
187
|
+
function startPress(event: PointerEvent) {
|
|
188
|
+
if (event.pointerType !== 'touch' || !wantOpen || !(event.target instanceof Element)) return;
|
|
189
|
+
const button = event.target.closest('button[aria-label]');
|
|
190
|
+
if (!button) return;
|
|
191
|
+
clearTimeout(pressTimer);
|
|
192
|
+
pressTimer = setTimeout(() => {
|
|
193
|
+
// Keyboard shortcuts in the label mean nothing on a phone.
|
|
194
|
+
hint = (button.getAttribute('aria-label') ?? '').replace(/\s*\([A-Z]\)$/, '');
|
|
195
|
+
swallowClick = true;
|
|
196
|
+
}, LONG_PRESS_MS);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function endPress() {
|
|
200
|
+
clearTimeout(pressTimer);
|
|
201
|
+
if (!hint) return;
|
|
202
|
+
clearTimeout(hintTimer);
|
|
203
|
+
hintTimer = setTimeout(() => (hint = null), HINT_LINGER_MS);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function swallowLongPressClick(event: MouseEvent) {
|
|
207
|
+
if (!swallowClick) return;
|
|
208
|
+
swallowClick = false;
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
event.stopPropagation();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function trackMenu(open: boolean) {
|
|
214
|
+
menusOpen += open ? 1 : -1;
|
|
215
|
+
if (!open && !touch.current) scheduleCollapse(250);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Buttons in the row, in order, so the stagger index stays right when some are hidden.
|
|
219
|
+
const buttons = $derived(
|
|
220
|
+
[
|
|
221
|
+
showDisplay && 'look',
|
|
222
|
+
showSceneManager && 'scene',
|
|
223
|
+
'measure',
|
|
224
|
+
'fit',
|
|
225
|
+
showFullscreen && 'full',
|
|
226
|
+
'more'
|
|
227
|
+
].filter(Boolean) as string[]
|
|
228
|
+
);
|
|
229
|
+
const idx = (id: string) => buttons.indexOf(id);
|
|
230
|
+
|
|
231
|
+
const BTN =
|
|
232
|
+
'relative grid size-8.5 shrink-0 place-items-center rounded-lg text-foreground outline-none transition-colors hover:bg-hover hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring aria-pressed:text-foreground data-[state=open]:bg-selected data-[state=open]:text-foreground pointer-coarse:size-11';
|
|
233
|
+
const DOT =
|
|
234
|
+
'aria-pressed:after:absolute aria-pressed:after:bottom-0.5 aria-pressed:after:size-1 aria-pressed:after:rounded-full aria-pressed:after:bg-primary';
|
|
235
|
+
</script>
|
|
236
|
+
|
|
237
|
+
<!-- eslint-disable shadcn/no-inline-styles -- the pill animates between measured pixel sizes and staggered per-item delays; no class can express those -->
|
|
238
|
+
|
|
239
|
+
<svelte:window onpointermove={handlePointerMove} onpointerdown={handleWindowPointerDown} />
|
|
240
|
+
|
|
241
|
+
<!-- Resting state is a pill; it grows into the row. Only the container is clickable while collapsed. -->
|
|
242
|
+
<div
|
|
243
|
+
bind:this={dockEl}
|
|
244
|
+
role="toolbar"
|
|
245
|
+
aria-label={t.toolsMenu}
|
|
246
|
+
tabindex="-1"
|
|
247
|
+
class="backdrop-blur-md absolute left-1/2 z-50 -translate-x-1/2 overflow-hidden transition-colors select-none {hidden
|
|
248
|
+
? 'pointer-events-none opacity-0'
|
|
249
|
+
: ''} {wantOpen
|
|
250
|
+
? 'shadow-md border border-border-strong bg-card/75'
|
|
251
|
+
: touch.current
|
|
252
|
+
? 'shadow-lg cursor-pointer border border-border bg-background/90'
|
|
253
|
+
: nightOn
|
|
254
|
+
? 'border-white/25 bg-white/35 hover:bg-white/70 cursor-pointer border'
|
|
255
|
+
: 'shadow-sm cursor-pointer border border-border-strong bg-card/90 hover:bg-card'}"
|
|
256
|
+
style="{containerStyle};-webkit-touch-callout:none"
|
|
257
|
+
onclick={openFromCollapsed}
|
|
258
|
+
onkeydown={(e) => (e.key === 'Escape' ? (engaged = false) : undefined)}
|
|
259
|
+
onfocusin={() => (focusWithin = true)}
|
|
260
|
+
onfocusout={(e) => {
|
|
261
|
+
if (!dockEl?.contains(e.relatedTarget as Node | null)) focusWithin = false;
|
|
262
|
+
}}
|
|
263
|
+
onpointerdown={startPress}
|
|
264
|
+
onpointerup={endPress}
|
|
265
|
+
onpointercancel={endPress}
|
|
266
|
+
onclickcapture={swallowLongPressClick}
|
|
267
|
+
oncontextmenu={(e) => touch.current && e.preventDefault()}
|
|
268
|
+
>
|
|
269
|
+
{#if touch.current}
|
|
270
|
+
<span
|
|
271
|
+
class="inset-0 pointer-events-none absolute grid place-items-center text-foreground"
|
|
272
|
+
style={glyphStyle}
|
|
273
|
+
aria-hidden="true"
|
|
274
|
+
>
|
|
275
|
+
<Settings2 class="size-5" />
|
|
276
|
+
</span>
|
|
277
|
+
{/if}
|
|
278
|
+
|
|
279
|
+
<div
|
|
280
|
+
bind:offsetWidth={rowWidth}
|
|
281
|
+
class="gap-0.5 mx-auto flex w-max items-center"
|
|
282
|
+
inert={!wantOpen}
|
|
283
|
+
>
|
|
284
|
+
{#if showDisplay}
|
|
285
|
+
<div style={itemStyle(idx('look'))}>
|
|
286
|
+
<DropdownMenu.Root onOpenChange={trackMenu}>
|
|
287
|
+
<DropdownMenu.Trigger>
|
|
288
|
+
{#snippet child({ props })}
|
|
289
|
+
<button {...props} class={BTN} title={t.display} aria-label={t.display}>
|
|
290
|
+
<Palette class="size-4.5" />
|
|
291
|
+
</button>
|
|
292
|
+
{/snippet}
|
|
293
|
+
</DropdownMenu.Trigger>
|
|
294
|
+
<DropdownMenu.Content
|
|
295
|
+
side="top"
|
|
296
|
+
align="center"
|
|
297
|
+
sideOffset={12}
|
|
298
|
+
variant="glass"
|
|
299
|
+
class="min-w-52 z-10001 w-auto whitespace-nowrap"
|
|
300
|
+
>
|
|
301
|
+
<DropdownMenu.RadioGroup
|
|
302
|
+
value={renderStyle}
|
|
303
|
+
onValueChange={(look) => onSetLook(look as Look)}
|
|
304
|
+
>
|
|
305
|
+
{#each styleOptions as { look, label } (look)}
|
|
306
|
+
<DropdownMenu.RadioItem value={look} closeOnSelect={false}>
|
|
307
|
+
{label}
|
|
308
|
+
</DropdownMenu.RadioItem>
|
|
309
|
+
{/each}
|
|
310
|
+
</DropdownMenu.RadioGroup>
|
|
311
|
+
<DropdownMenu.Separator />
|
|
312
|
+
<DropdownMenu.CheckboxItem
|
|
313
|
+
switch
|
|
314
|
+
checked={edgesVisible}
|
|
315
|
+
onCheckedChange={onToggleEdges}
|
|
316
|
+
>
|
|
317
|
+
<Spline />
|
|
318
|
+
{t.edges}
|
|
319
|
+
<DropdownMenu.Shortcut class="pointer-coarse:hidden">E</DropdownMenu.Shortcut>
|
|
320
|
+
</DropdownMenu.CheckboxItem>
|
|
321
|
+
</DropdownMenu.Content>
|
|
322
|
+
</DropdownMenu.Root>
|
|
323
|
+
</div>
|
|
324
|
+
{/if}
|
|
325
|
+
|
|
326
|
+
{#if showSceneManager}
|
|
327
|
+
<div style={itemStyle(idx('scene'))}>
|
|
328
|
+
<button
|
|
329
|
+
class="{BTN} {DOT}"
|
|
330
|
+
title="{t.sceneManager} (S)"
|
|
331
|
+
aria-label={t.sceneManager}
|
|
332
|
+
aria-pressed={sceneManagerOpen}
|
|
333
|
+
onclick={onToggleSceneManager}
|
|
334
|
+
>
|
|
335
|
+
<Layers class="size-4.5" />
|
|
336
|
+
</button>
|
|
337
|
+
</div>
|
|
338
|
+
{/if}
|
|
339
|
+
|
|
340
|
+
<div style={itemStyle(idx('measure'))}>
|
|
341
|
+
<button
|
|
342
|
+
class="{BTN} {DOT}"
|
|
343
|
+
title="{t.measure} (M)"
|
|
344
|
+
aria-label={t.measure}
|
|
345
|
+
aria-pressed={measureActive}
|
|
346
|
+
onclick={onToggleMeasure}
|
|
347
|
+
>
|
|
348
|
+
<Ruler class="size-4.5" />
|
|
349
|
+
</button>
|
|
350
|
+
</div>
|
|
351
|
+
|
|
352
|
+
<div style={itemStyle(idx('fit'))}>
|
|
353
|
+
<button class={BTN} title="{t.fitToView} (F)" aria-label="{t.fitToView} (F)" onclick={onFit}>
|
|
354
|
+
<LocateFixed class="size-4.5" />
|
|
355
|
+
</button>
|
|
356
|
+
</div>
|
|
357
|
+
|
|
358
|
+
{#if showFullscreen}
|
|
359
|
+
<div style={itemStyle(idx('full'))}>
|
|
360
|
+
<button
|
|
361
|
+
class={BTN}
|
|
362
|
+
title={isFullscreen ? t.exitFullscreen : t.fullscreen}
|
|
363
|
+
aria-label={isFullscreen ? t.exitFullscreen : t.fullscreen}
|
|
364
|
+
onclick={onToggleFullscreen}
|
|
365
|
+
>
|
|
366
|
+
{#if isFullscreen}<Minimize class="size-4.5" />{:else}<Maximize class="size-4.5" />{/if}
|
|
367
|
+
</button>
|
|
368
|
+
</div>
|
|
369
|
+
{/if}
|
|
370
|
+
|
|
371
|
+
<div style={itemStyle(idx('more'))}>
|
|
372
|
+
<DropdownMenu.Root onOpenChange={trackMenu}>
|
|
373
|
+
<DropdownMenu.Trigger>
|
|
374
|
+
{#snippet child({ props })}
|
|
375
|
+
<button {...props} class={BTN} title={t.toolsMenu} aria-label={t.toolsMenu}>
|
|
376
|
+
<Ellipsis class="size-4.5" />
|
|
377
|
+
</button>
|
|
378
|
+
{/snippet}
|
|
379
|
+
</DropdownMenu.Trigger>
|
|
380
|
+
<DropdownMenu.Content
|
|
381
|
+
side="top"
|
|
382
|
+
align="end"
|
|
383
|
+
sideOffset={12}
|
|
384
|
+
variant="glass"
|
|
385
|
+
class="min-w-60 z-10001 w-auto whitespace-nowrap"
|
|
386
|
+
>
|
|
387
|
+
<DropdownMenu.Label>{t.views}</DropdownMenu.Label>
|
|
388
|
+
<div class="gap-1 px-1 pb-1 grid grid-cols-4">
|
|
389
|
+
{#each viewPresets as { preset, label } (preset)}
|
|
390
|
+
<DropdownMenu.Item
|
|
391
|
+
closeOnSelect={false}
|
|
392
|
+
onSelect={() => onSetView(preset)}
|
|
393
|
+
variant="chip"
|
|
394
|
+
>
|
|
395
|
+
{label}
|
|
396
|
+
</DropdownMenu.Item>
|
|
397
|
+
{/each}
|
|
398
|
+
</div>
|
|
399
|
+
|
|
400
|
+
<DropdownMenu.Separator />
|
|
401
|
+
|
|
402
|
+
<DropdownMenu.CheckboxItem
|
|
403
|
+
switch
|
|
404
|
+
checked={projection === 'orthographic'}
|
|
405
|
+
onCheckedChange={onToggleProjection}
|
|
406
|
+
>
|
|
407
|
+
<Cuboid />
|
|
408
|
+
{t.switchToOrthographic}
|
|
409
|
+
<DropdownMenu.Shortcut class="pointer-coarse:hidden">O</DropdownMenu.Shortcut>
|
|
410
|
+
</DropdownMenu.CheckboxItem>
|
|
411
|
+
|
|
412
|
+
{#if showGrid}
|
|
413
|
+
<DropdownMenu.CheckboxItem switch checked={gridVisible} onCheckedChange={onToggleGrid}>
|
|
414
|
+
<Grid3x3 />
|
|
415
|
+
{t.grid}
|
|
416
|
+
<DropdownMenu.Shortcut class="pointer-coarse:hidden">G</DropdownMenu.Shortcut>
|
|
417
|
+
</DropdownMenu.CheckboxItem>
|
|
418
|
+
{/if}
|
|
419
|
+
|
|
420
|
+
{#if showDisplay}
|
|
421
|
+
<DropdownMenu.CheckboxItem switch checked={nightOn} onCheckedChange={onToggleNight}>
|
|
422
|
+
<Moon />
|
|
423
|
+
{t.nightMode}
|
|
424
|
+
<DropdownMenu.Shortcut class="pointer-coarse:hidden">N</DropdownMenu.Shortcut>
|
|
425
|
+
</DropdownMenu.CheckboxItem>
|
|
426
|
+
{/if}
|
|
427
|
+
|
|
428
|
+
{#if showScreenshot}
|
|
429
|
+
<DropdownMenu.Separator />
|
|
430
|
+
{/if}
|
|
431
|
+
|
|
432
|
+
{#if showScreenshot}
|
|
433
|
+
<DropdownMenu.Item onSelect={onScreenshot}>
|
|
434
|
+
<Camera />
|
|
435
|
+
{t.screenshot}
|
|
436
|
+
</DropdownMenu.Item>
|
|
437
|
+
{/if}
|
|
438
|
+
</DropdownMenu.Content>
|
|
439
|
+
</DropdownMenu.Root>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
{#if hint}
|
|
445
|
+
<div
|
|
446
|
+
role="status"
|
|
447
|
+
class="text-xs font-medium px-2.5 py-1 shadow-md pointer-events-none absolute left-1/2 z-50 -translate-x-1/2 rounded-md border border-border-strong bg-card text-foreground"
|
|
448
|
+
style="bottom:calc({bottom} + {EXPANDED_H + 8}px)"
|
|
449
|
+
>
|
|
450
|
+
{hint}
|
|
451
|
+
</div>
|
|
452
|
+
{/if}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CameraProjection, Look, ViewPreset } from '@selvajs/visualization/render';
|
|
2
|
+
import type { ViewerMessages } from '../../i18n/messages.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
t: ViewerMessages;
|
|
5
|
+
/** Fades the dock out while a host drawer covers the viewer. */
|
|
6
|
+
hidden?: boolean;
|
|
7
|
+
showDisplay: boolean;
|
|
8
|
+
showGrid: boolean;
|
|
9
|
+
showSceneManager: boolean;
|
|
10
|
+
showScreenshot: boolean;
|
|
11
|
+
showFullscreen: boolean;
|
|
12
|
+
styleOptions: {
|
|
13
|
+
look: Look;
|
|
14
|
+
label: string;
|
|
15
|
+
}[];
|
|
16
|
+
viewPresets: {
|
|
17
|
+
preset: ViewPreset;
|
|
18
|
+
label: string;
|
|
19
|
+
}[];
|
|
20
|
+
renderStyle: Look;
|
|
21
|
+
nightOn: boolean;
|
|
22
|
+
edgesVisible: boolean;
|
|
23
|
+
measureActive: boolean;
|
|
24
|
+
gridVisible: boolean;
|
|
25
|
+
sceneManagerOpen: boolean;
|
|
26
|
+
projection: CameraProjection;
|
|
27
|
+
isFullscreen: boolean;
|
|
28
|
+
onSetLook: (look: Look) => void;
|
|
29
|
+
onToggleNight: () => void;
|
|
30
|
+
onToggleEdges: () => void;
|
|
31
|
+
onToggleMeasure: () => void;
|
|
32
|
+
onToggleGrid: () => void;
|
|
33
|
+
onToggleSceneManager: () => void;
|
|
34
|
+
onToggleProjection: () => void;
|
|
35
|
+
onSetView: (preset: ViewPreset) => void;
|
|
36
|
+
onFit: () => void;
|
|
37
|
+
onScreenshot: () => void;
|
|
38
|
+
onToggleFullscreen: () => void;
|
|
39
|
+
}
|
|
40
|
+
declare const ViewerDock: import("svelte").Component<Props, {}, "">;
|
|
41
|
+
type ViewerDock = ReturnType<typeof ViewerDock>;
|
|
42
|
+
export default ViewerDock;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Component } from 'svelte';
|
|
2
|
-
import { type FooterItem } from '../contexts/footerContext.svelte';
|
|
2
|
+
import { type FooterItem } from '../contexts/footerContext.svelte.js';
|
|
3
3
|
export type FooterItemConfig<P extends Record<string, unknown> = Record<string, unknown>> = Omit<FooterItem<P>, 'position' | 'priority'> & Partial<Pick<FooterItem<P>, 'position' | 'priority'>>;
|
|
4
4
|
/**
|
|
5
5
|
* Register a footer item for the lifetime of the calling component.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getContext, onMount, onDestroy } from 'svelte';
|
|
2
|
-
import { FOOTER_CONTEXT_KEY } from '../contexts/footerContext.svelte';
|
|
2
|
+
import { FOOTER_CONTEXT_KEY } from '../contexts/footerContext.svelte.js';
|
|
3
3
|
/**
|
|
4
4
|
* Register a footer item for the lifetime of the calling component.
|
|
5
5
|
*
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ProgressPayload } from '@selvajs/schemas';
|
|
2
|
+
import type { LiveSolveState } from '@selvajs/solve/client';
|
|
3
|
+
/** A progress bar's width (0–1) and how long its transition to that width runs. */
|
|
4
|
+
export interface ProgressBar {
|
|
5
|
+
width: number;
|
|
6
|
+
ms: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The live channel's progress reports, smoothed for display. `headline` is the first source's
|
|
10
|
+
* report, held long enough to read; `bars` is the width each source's bar should animate to.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createLiveProgress(getLive: () => LiveSolveState): {
|
|
13
|
+
readonly progress: ProgressPayload[];
|
|
14
|
+
readonly headline: ProgressPayload | undefined;
|
|
15
|
+
readonly bars: Readonly<Record<string, ProgressBar>>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* The live channel's progress reports, smoothed for display. `headline` is the first source's
|
|
4
|
+
* report, held long enough to read; `bars` is the width each source's bar should animate to.
|
|
5
|
+
*/
|
|
6
|
+
export function createLiveProgress(getLive) {
|
|
7
|
+
const progress = $derived([...getLive().progress.values()]);
|
|
8
|
+
// A report only arrives when a step starts, so a bar that just shows `fraction` stands still
|
|
9
|
+
// through the step and then jumps. When the plugin knows how long the step took last time, the
|
|
10
|
+
// bar runs linearly to where the step will end, over that time. Steps are weighted by time, so
|
|
11
|
+
// linear gives one steady speed across the solve; any easing curve visibly speeds up and
|
|
12
|
+
// crawls within each step. A slower run waits at the step's end; a faster one snaps ahead.
|
|
13
|
+
let bars = $state.raw({});
|
|
14
|
+
// Any live event re-runs the effect below. Only a source with a new report may re-snap;
|
|
15
|
+
// the rest keep easing where they are.
|
|
16
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- bookkeeping for the effect below, never rendered
|
|
17
|
+
let seen = new Map();
|
|
18
|
+
let targets = {};
|
|
19
|
+
$effect(() => {
|
|
20
|
+
const snapped = {};
|
|
21
|
+
const eased = {};
|
|
22
|
+
const current = untrack(() => bars);
|
|
23
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- bookkeeping for this effect; reactive reads here would re-trigger it
|
|
24
|
+
const nextSeen = new Map();
|
|
25
|
+
for (const p of progress) {
|
|
26
|
+
if (p.fraction === undefined)
|
|
27
|
+
continue;
|
|
28
|
+
const key = p.source ?? '';
|
|
29
|
+
nextSeen.set(key, p);
|
|
30
|
+
if (seen.get(key) === p && current[key]) {
|
|
31
|
+
snapped[key] = current[key];
|
|
32
|
+
// This run's cleanup cancelled the frame that would have started the ease.
|
|
33
|
+
if (targets[key] && current[key] !== targets[key])
|
|
34
|
+
eased[key] = targets[key];
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
snapped[key] = { width: p.fraction, ms: 150 };
|
|
38
|
+
if (p.nextFraction !== undefined && p.stepMs !== undefined) {
|
|
39
|
+
eased[key] = { width: p.nextFraction, ms: p.stepMs };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
seen = nextSeen;
|
|
43
|
+
targets = eased;
|
|
44
|
+
bars = snapped;
|
|
45
|
+
if (Object.keys(eased).length === 0)
|
|
46
|
+
return;
|
|
47
|
+
// Two frames: the snapped width must be painted before the eased one is set, or the
|
|
48
|
+
// browser folds both into one style change and there is nothing to transition from.
|
|
49
|
+
let frame = requestAnimationFrame(() => {
|
|
50
|
+
frame = requestAnimationFrame(() => (bars = { ...snapped, ...eased }));
|
|
51
|
+
});
|
|
52
|
+
return () => cancelAnimationFrame(frame);
|
|
53
|
+
});
|
|
54
|
+
// Steps a few milliseconds long would swap the headline faster than it can be read. Each one
|
|
55
|
+
// stays up for at least this long; steps that end sooner are skipped in the label but still
|
|
56
|
+
// count in the bar. The label and its step count move together so they never disagree.
|
|
57
|
+
const HEADLINE_MIN_MS = 200;
|
|
58
|
+
let headline = $state.raw(undefined);
|
|
59
|
+
let headlineAt = 0;
|
|
60
|
+
$effect(() => {
|
|
61
|
+
const next = progress[0];
|
|
62
|
+
const shown = untrack(() => headline);
|
|
63
|
+
if (next?.label === shown?.label && next?.done === shown?.done) {
|
|
64
|
+
headline = next;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const show = () => {
|
|
68
|
+
headline = next;
|
|
69
|
+
headlineAt = performance.now();
|
|
70
|
+
};
|
|
71
|
+
const wait = HEADLINE_MIN_MS - (performance.now() - headlineAt);
|
|
72
|
+
if (!shown || wait <= 0) {
|
|
73
|
+
show();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const timer = setTimeout(show, wait);
|
|
77
|
+
return () => clearTimeout(timer);
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
get progress() {
|
|
81
|
+
return progress;
|
|
82
|
+
},
|
|
83
|
+
get headline() {
|
|
84
|
+
return headline;
|
|
85
|
+
},
|
|
86
|
+
get bars() {
|
|
87
|
+
return bars;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Average over SLOW_THRESHOLD_MS: shown immediately
|
|
7
|
-
* - Between the two: shown after a proportional slice of ANIMATION_DELAY
|
|
8
|
-
* - First solve: shown immediately, there is no history yet
|
|
2
|
+
* When to show that a solve is running. A solve that ends within `SHOW_AFTER_MS` shows nothing:
|
|
3
|
+
* the result updating is feedback enough, and a spinner that flashes for a frame reads as jank.
|
|
4
|
+
* Once shown, the indicator stays `MIN_VISIBLE_MS` for the same reason. `slow` turns on past
|
|
5
|
+
* `SLOW_AFTER_MS`, the case of a Rhino.Compute round trip or a heavy definition.
|
|
9
6
|
*
|
|
10
7
|
* `freezesDuringSolve` is for a host that can't paint while it solves (an embedded WebView on
|
|
11
|
-
* the solver's thread).
|
|
12
|
-
*
|
|
8
|
+
* the solver's thread). A delay can't run there, so the indicator shows on every solve, before
|
|
9
|
+
* the solve takes the thread: it is the only place that host can say Esc aborts.
|
|
13
10
|
*/
|
|
14
11
|
export declare function createSolvingIndicator(isSolving: () => boolean, options?: {
|
|
15
12
|
freezesDuringSolve?: boolean;
|
|
16
13
|
}): {
|
|
17
14
|
readonly show: boolean;
|
|
15
|
+
readonly slow: boolean;
|
|
18
16
|
};
|