@selvajs/ui 6.6.0-beta.8 → 7.0.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 +95 -37
- package/dist/components/compute/AppLayout.svelte.d.ts +18 -1
- 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 +9 -21
- package/dist/components/compute/SolveMessages.svelte +101 -87
- package/dist/components/compute/SolveMessages.svelte.d.ts +12 -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 +8 -6
- package/dist/components/layout/PageHeader.svelte +3 -3
- package/dist/components/layout/SideNav.svelte +56 -15
- package/dist/components/layout/SubNav.svelte +2 -2
- package/dist/components/preview/ChartOutput.svelte +158 -62
- package/dist/components/preview/Group.svelte +14 -9
- package/dist/components/preview/HelpButton.svelte +1 -1
- package/dist/components/preview/ImageOutput.svelte +16 -11
- package/dist/components/preview/InputControl.svelte +115 -50
- package/dist/components/preview/InputControl.svelte.d.ts +5 -1
- 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 +65 -33
- package/dist/components/preview/TabContent.svelte.d.ts +5 -1
- package/dist/components/preview/TabLayout.svelte +29 -8
- package/dist/components/preview/TabLayout.svelte.d.ts +5 -0
- package/dist/components/preview/inputs/CheckboxInput.svelte +1 -1
- package/dist/components/preview/inputs/ChecklistInput.svelte +11 -6
- package/dist/components/preview/inputs/ChecklistInput.svelte.d.ts +2 -1
- 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 +18 -6
- package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +2 -1
- package/dist/components/preview/inputs/FileInput.svelte +71 -75
- package/dist/components/preview/inputs/GeometryInput.svelte +128 -0
- package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +21 -0
- package/dist/components/preview/inputs/NumberInput.svelte +8 -8
- package/dist/components/preview/inputs/OptionGlyph.svelte +29 -0
- package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +8 -0
- package/dist/components/preview/inputs/SegmentedInput.svelte +45 -0
- package/dist/components/preview/inputs/SegmentedInput.svelte.d.ts +12 -0
- package/dist/components/preview/inputs/TextInput.svelte +5 -5
- package/dist/components/preview/inputs/TileInput.svelte +83 -0
- package/dist/components/preview/inputs/TileInput.svelte.d.ts +12 -0
- package/dist/components/preview/inputs/index.d.ts +3 -0
- package/dist/components/preview/inputs/index.js +3 -0
- 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 +245 -19
- package/dist/components/primitives/SolvingIndicator.svelte.d.ts +15 -0
- 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 +9 -7
- package/dist/components/primitives/button/button.svelte.d.ts +19 -16
- 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 +11 -3
- package/dist/components/primitives/toggle/toggle.svelte.d.ts +13 -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 +135 -185
- package/dist/components/viewer/Viewer.svelte.d.ts +7 -2
- package/dist/components/viewer/ViewerDock.svelte +404 -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 +11 -7
- package/dist/compute/solving.svelte.js +64 -45
- package/dist/constants.d.ts +6 -8
- package/dist/constants.js +8 -11
- package/dist/contexts/hostContext.svelte.d.ts +39 -0
- package/dist/contexts/hostContext.svelte.js +9 -0
- 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 +50 -0
- package/dist/i18n/messages.js +84 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/public.d.ts +1 -0
- package/dist/public.js +1 -0
- package/dist/schema/host-support.d.ts +29 -0
- package/dist/schema/host-support.js +97 -0
- package/dist/schema/option-display.d.ts +12 -0
- package/dist/schema/option-display.js +29 -0
- package/dist/schema/param-exporter.d.ts +4 -1
- package/dist/schema/param-exporter.js +10 -6
- package/dist/schema/visibility-rules.d.ts +7 -1
- package/dist/schema/visibility-rules.js +17 -0
- package/dist/styles/base.css +94 -84
- package/dist/utils/color-space.d.ts +21 -0
- package/dist/utils/color-space.js +90 -0
- package/dist/utils/file-download.js +6 -10
- package/dist/utils/host-files.d.ts +12 -0
- package/dist/utils/host-files.js +46 -0
- package/dist/utils/webp-to-png.d.ts +10 -0
- package/dist/utils/webp-to-png.js +41 -0
- package/package.json +31 -23
- package/src/lib/components/ErrorScreen.svelte +1 -1
- package/src/lib/components/compute/AppLayout.svelte +96 -38
- 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 +9 -21
- package/src/lib/components/compute/SolveMessages.svelte +103 -89
- 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 +8 -6
- package/src/lib/components/layout/PageHeader.svelte +3 -3
- package/src/lib/components/layout/SideNav.svelte +56 -15
- package/src/lib/components/layout/SubNav.svelte +2 -2
- package/src/lib/components/preview/ChartOutput.svelte +158 -62
- package/src/lib/components/preview/Group.svelte +14 -9
- package/src/lib/components/preview/HelpButton.svelte +1 -1
- package/src/lib/components/preview/ImageOutput.svelte +16 -11
- package/src/lib/components/preview/InputControl.svelte +115 -50
- 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 +65 -33
- package/src/lib/components/preview/TabLayout.svelte +29 -8
- package/src/lib/components/preview/inputs/CheckboxInput.svelte +1 -1
- package/src/lib/components/preview/inputs/ChecklistInput.svelte +11 -6
- package/src/lib/components/preview/inputs/ColorInput.svelte +356 -14
- package/src/lib/components/preview/inputs/DropdownInput.svelte +18 -6
- package/src/lib/components/preview/inputs/FileInput.svelte +71 -75
- package/src/lib/components/preview/inputs/GeometryInput.svelte +128 -0
- package/src/lib/components/preview/inputs/NumberInput.svelte +8 -8
- package/src/lib/components/preview/inputs/OptionGlyph.svelte +29 -0
- package/src/lib/components/preview/inputs/SegmentedInput.svelte +45 -0
- package/src/lib/components/preview/inputs/TextInput.svelte +5 -5
- package/src/lib/components/preview/inputs/TileInput.svelte +83 -0
- package/src/lib/components/preview/inputs/index.ts +3 -0
- 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 +245 -19
- 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 +9 -7
- 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 +12 -4
- 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 +136 -186
- package/src/lib/components/viewer/ViewerDock.svelte +404 -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 +66 -50
- package/src/lib/constants.ts +8 -11
- package/src/lib/contexts/hostContext.svelte.ts +51 -0
- package/src/lib/features/chart/plotly-compat.ts +141 -0
- package/src/lib/i18n/messages.ts +139 -0
- package/src/lib/index.ts +22 -0
- package/src/lib/public.ts +1 -0
- package/src/lib/schema/host-support.ts +129 -0
- package/src/lib/schema/option-display.ts +44 -0
- package/src/lib/schema/param-exporter.ts +10 -7
- package/src/lib/schema/visibility-rules.ts +27 -1
- package/src/lib/styles/base.css +94 -84
- package/src/lib/utils/color-space.ts +107 -0
- package/src/lib/utils/file-download.ts +7 -11
- package/src/lib/utils/host-files.ts +61 -0
- package/src/lib/utils/webp-to-png.ts +48 -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
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Input } from '../../primitives/input';
|
|
3
|
-
import { Button } from '../../primitives/button';
|
|
4
|
-
import { Label } from '../../primitives/label';
|
|
5
|
-
import { toast } from '../../primitives/sonner';
|
|
2
|
+
import { Input } from '../../primitives/input/index.js';
|
|
3
|
+
import { Button } from '../../primitives/button/index.js';
|
|
4
|
+
import { Label } from '../../primitives/label/index.js';
|
|
5
|
+
import { toast } from '../../primitives/sonner/index.js';
|
|
6
6
|
import { FileUp, Link, CircleAlert, CircleCheck } from '@lucide/svelte';
|
|
7
|
-
import { APP_DEFAULTS } from '../../../constants';
|
|
8
|
-
import { getLocaleContext } from '../../../i18n/localeContext.svelte';
|
|
9
|
-
import { formatMessage } from '../../../i18n/messages';
|
|
7
|
+
import { APP_DEFAULTS } from '../../../constants.js';
|
|
8
|
+
import { getLocaleContext } from '../../../i18n/localeContext.svelte.js';
|
|
9
|
+
import { formatMessage } from '../../../i18n/messages.js';
|
|
10
|
+
import { pickFile } from '../../../utils/host-files.js';
|
|
11
|
+
import {
|
|
12
|
+
acceptsFileEnding,
|
|
13
|
+
isWebp,
|
|
14
|
+
shouldConvertWebp,
|
|
15
|
+
webpToPng
|
|
16
|
+
} from '../../../utils/webp-to-png.js';
|
|
10
17
|
|
|
11
18
|
interface Props {
|
|
12
19
|
value?: string;
|
|
@@ -40,7 +47,6 @@
|
|
|
40
47
|
activeMode = effectiveModes.includes(preferred) ? preferred : effectiveModes[0];
|
|
41
48
|
});
|
|
42
49
|
|
|
43
|
-
let fileInput: HTMLInputElement | null = $state(null);
|
|
44
50
|
let uploadedFileName = $state('');
|
|
45
51
|
let urlInput = $state('');
|
|
46
52
|
let isDragging = $state(false);
|
|
@@ -94,9 +100,27 @@
|
|
|
94
100
|
return ext.toLowerCase();
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
// Runs before the size cap: the PNG is larger than the WebP it came from. A WebP already over
|
|
104
|
+
// the cap is passed through unconverted, so the cap rejects it without a full decode.
|
|
105
|
+
async function prepare(
|
|
106
|
+
blob: Blob,
|
|
107
|
+
fileEnding: string
|
|
108
|
+
): Promise<{ blob: Blob; fileEnding: string }> {
|
|
109
|
+
if (blob.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) return { blob, fileEnding };
|
|
110
|
+
if (!shouldConvertWebp(fileEnding, acceptedFormats)) return { blob, fileEnding };
|
|
111
|
+
return { blob: await webpToPng(blob), fileEnding: '.png' };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function readBase64(blob: Blob): Promise<string> {
|
|
115
|
+
return new Promise<string>((resolve, reject) => {
|
|
116
|
+
const reader = new FileReader();
|
|
117
|
+
reader.onload = (e) => {
|
|
118
|
+
const result = e.target?.result as string;
|
|
119
|
+
resolve(result.includes(',') ? result.split(',')[1] : result);
|
|
120
|
+
};
|
|
121
|
+
reader.onerror = () => reject(new Error(t.fileReadFailed));
|
|
122
|
+
reader.readAsDataURL(blob);
|
|
123
|
+
});
|
|
100
124
|
}
|
|
101
125
|
|
|
102
126
|
function isCorsError(error: unknown): boolean {
|
|
@@ -138,14 +162,16 @@
|
|
|
138
162
|
return;
|
|
139
163
|
}
|
|
140
164
|
|
|
141
|
-
const
|
|
142
|
-
const
|
|
165
|
+
const fetched = await response.blob();
|
|
166
|
+
const requestedEnding = (await isWebp(fetched)) ? '.webp' : getFileExtension(urlInput);
|
|
143
167
|
|
|
144
|
-
if (!
|
|
145
|
-
urlError = { message: formatNotAccepted(
|
|
168
|
+
if (!acceptsFileEnding(requestedEnding, acceptedFormats)) {
|
|
169
|
+
urlError = { message: formatNotAccepted(requestedEnding), isCors: false };
|
|
146
170
|
return;
|
|
147
171
|
}
|
|
148
172
|
|
|
173
|
+
const { blob, fileEnding } = await prepare(fetched, requestedEnding);
|
|
174
|
+
|
|
149
175
|
const maxSize = APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES;
|
|
150
176
|
if (blob.size > maxSize) {
|
|
151
177
|
urlError = {
|
|
@@ -155,15 +181,7 @@
|
|
|
155
181
|
return;
|
|
156
182
|
}
|
|
157
183
|
|
|
158
|
-
const base64Data = await
|
|
159
|
-
const reader = new FileReader();
|
|
160
|
-
reader.onload = (e) => {
|
|
161
|
-
const result = e.target?.result as string;
|
|
162
|
-
resolve(result.includes(',') ? result.split(',')[1] : result);
|
|
163
|
-
};
|
|
164
|
-
reader.onerror = () => reject(new Error(t.fileReadFailed));
|
|
165
|
-
reader.readAsDataURL(blob);
|
|
166
|
-
});
|
|
184
|
+
const base64Data = await readBase64(blob);
|
|
167
185
|
const data = JSON.stringify({ file: base64Data, type: 'base64', fileEnding });
|
|
168
186
|
value = data;
|
|
169
187
|
urlSuccess = formatMessage(t.fileLoaded, {
|
|
@@ -206,48 +224,39 @@
|
|
|
206
224
|
}
|
|
207
225
|
}
|
|
208
226
|
|
|
209
|
-
function
|
|
210
|
-
const
|
|
211
|
-
const file = target.files?.[0];
|
|
212
|
-
if (!file) return;
|
|
213
|
-
|
|
214
|
-
const fileEnding = getFileExtension(file.name);
|
|
215
|
-
|
|
216
|
-
if (!isValidFileExtension(fileEnding)) {
|
|
217
|
-
toast.error(formatNotAccepted(fileEnding));
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
227
|
+
async function handleFile(file: File) {
|
|
228
|
+
const requestedEnding = getFileExtension(file.name);
|
|
220
229
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// currently LOOSER than the server's COMPUTE_REQUEST_MAX_BYTES (see the TEMP
|
|
224
|
-
// note in constants.ts) — some files pass here and still 413. The URL import
|
|
225
|
-
// path applies the same cap.
|
|
226
|
-
if (file.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) {
|
|
227
|
-
toast.error(formatTooLarge(file.size));
|
|
230
|
+
if (!acceptsFileEnding(requestedEnding, acceptedFormats)) {
|
|
231
|
+
toast.error(formatNotAccepted(requestedEnding));
|
|
228
232
|
return;
|
|
229
233
|
}
|
|
230
234
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
try {
|
|
236
|
+
const { blob, fileEnding } = await prepare(file, requestedEnding);
|
|
237
|
+
|
|
238
|
+
// The file is base64-embedded into the compute request body, so without a
|
|
239
|
+
// client-side cap an oversize file comes back as an opaque 413. This cap is
|
|
240
|
+
// currently LOOSER than the server's COMPUTE_REQUEST_MAX_BYTES (see the TEMP
|
|
241
|
+
// note in constants.ts) — some files pass here and still 413. The URL import
|
|
242
|
+
// path applies the same cap.
|
|
243
|
+
if (blob.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) {
|
|
244
|
+
toast.error(formatTooLarge(blob.size));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
237
247
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
type: 'base64',
|
|
241
|
-
fileEnding
|
|
242
|
-
});
|
|
248
|
+
uploadedFileName = file.name;
|
|
249
|
+
const data = JSON.stringify({ file: await readBase64(blob), type: 'base64', fileEnding });
|
|
243
250
|
value = data;
|
|
244
251
|
onChange(data);
|
|
245
|
-
}
|
|
246
|
-
|
|
252
|
+
} catch (error) {
|
|
253
|
+
toast.error(error instanceof Error ? error.message : t.fileReadFailed);
|
|
254
|
+
}
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
function openFilePicker() {
|
|
250
|
-
|
|
257
|
+
async function openFilePicker() {
|
|
258
|
+
const file = await pickFile({ accept: acceptAttribute });
|
|
259
|
+
if (file) handleFile(file);
|
|
251
260
|
}
|
|
252
261
|
|
|
253
262
|
function handleDragOver(e: DragEvent) {
|
|
@@ -263,27 +272,14 @@
|
|
|
263
272
|
e.preventDefault();
|
|
264
273
|
isDragging = false;
|
|
265
274
|
|
|
266
|
-
const
|
|
267
|
-
if (
|
|
268
|
-
const fakeEvent = new Event('change');
|
|
269
|
-
const fakeTarget = { files: files } as HTMLInputElement;
|
|
270
|
-
Object.defineProperty(fakeEvent, 'target', { value: fakeTarget });
|
|
271
|
-
handleFileUpload(fakeEvent);
|
|
272
|
-
}
|
|
275
|
+
const file = e.dataTransfer?.files?.[0];
|
|
276
|
+
if (file) handleFile(file);
|
|
273
277
|
}
|
|
274
278
|
|
|
275
279
|
const acceptAttribute = $derived(acceptedFormats.length > 0 ? acceptedFormats.join(',') : '*');
|
|
276
280
|
</script>
|
|
277
281
|
|
|
278
282
|
<div class="gap-2.5 flex w-full flex-col">
|
|
279
|
-
<input
|
|
280
|
-
bind:this={fileInput}
|
|
281
|
-
type="file"
|
|
282
|
-
accept={acceptAttribute}
|
|
283
|
-
onchange={handleFileUpload}
|
|
284
|
-
class="hidden"
|
|
285
|
-
/>
|
|
286
|
-
|
|
287
283
|
{#if showToggle}
|
|
288
284
|
<div class="p-0.5 text-xs flex rounded-md bg-muted">
|
|
289
285
|
{#each effectiveModes as mode (mode)}
|
|
@@ -291,10 +287,10 @@
|
|
|
291
287
|
type="button"
|
|
292
288
|
onclick={() => (activeMode = mode)}
|
|
293
289
|
aria-pressed={activeMode === mode}
|
|
294
|
-
class={`px-3 py-1 font-medium flex-1 rounded-sm transition-colors ${
|
|
290
|
+
class={`px-3 py-1 font-medium flex-1 rounded-sm border transition-colors ${
|
|
295
291
|
activeMode === mode
|
|
296
|
-
? 'shadow-xs bg-
|
|
297
|
-
: 'text-muted-foreground hover:text-foreground'
|
|
292
|
+
? 'shadow-xs border-border-strong bg-raised text-foreground'
|
|
293
|
+
: 'border-transparent text-muted-foreground hover:text-foreground'
|
|
298
294
|
}`}
|
|
299
295
|
>
|
|
300
296
|
{mode === 'upload' ? t.fileModeUpload : t.fileModeUrl}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '../../primitives/button/index.js';
|
|
3
|
+
import type { GeometryPickResult, PickKind } from '../../../contexts/hostContext.svelte.js';
|
|
4
|
+
import { getLocaleContext } from '../../../i18n/localeContext.svelte.js';
|
|
5
|
+
import type { ViewerMessages } from '../../../i18n/messages.js';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
inputId: string;
|
|
9
|
+
/** The kinds of object the input takes; one kind names the button after it. */
|
|
10
|
+
kinds?: readonly PickKind[];
|
|
11
|
+
/** 1 picks a single object. */
|
|
12
|
+
atMost?: number;
|
|
13
|
+
/** What the host reports the param holds, such as "2 curves"; absent until something is picked. */
|
|
14
|
+
summary?: string;
|
|
15
|
+
/** Absent where this page may not pick, such as a browser tab beside the Rhino panel. */
|
|
16
|
+
onPick?: () => Promise<GeometryPickResult>;
|
|
17
|
+
onClear?: () => void;
|
|
18
|
+
/** Subscribes to what the host holds after any page picks or clears; returns an unsubscribe. */
|
|
19
|
+
watchSummary?: (listener: (summary: string | null) => void) => () => void;
|
|
20
|
+
/** Shown when the pick fails; the host's own message. */
|
|
21
|
+
onError?: (message: string) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
inputId,
|
|
27
|
+
kinds,
|
|
28
|
+
atMost,
|
|
29
|
+
summary,
|
|
30
|
+
onPick,
|
|
31
|
+
onClear,
|
|
32
|
+
watchSummary,
|
|
33
|
+
onError,
|
|
34
|
+
disabled = false
|
|
35
|
+
}: Props = $props();
|
|
36
|
+
|
|
37
|
+
const locale = getLocaleContext();
|
|
38
|
+
const t = $derived(locale.messages);
|
|
39
|
+
|
|
40
|
+
type PickLabels = readonly [one: keyof ViewerMessages, other: keyof ViewerMessages];
|
|
41
|
+
|
|
42
|
+
const ANY_LABELS: PickLabels = ['geometryPickAnyOne', 'geometryPickAnyOther'];
|
|
43
|
+
const KIND_LABELS: Record<PickKind, PickLabels> = {
|
|
44
|
+
point: ['geometryPickPointOne', 'geometryPickPointOther'],
|
|
45
|
+
pointCloud: ['geometryPickPointCloudOne', 'geometryPickPointCloudOther'],
|
|
46
|
+
curve: ['geometryPickCurveOne', 'geometryPickCurveOther'],
|
|
47
|
+
line: ['geometryPickLineOne', 'geometryPickLineOther'],
|
|
48
|
+
plane: ['geometryPickPlaneOne', 'geometryPickPlaneOther'],
|
|
49
|
+
surface: ['geometryPickSurfaceOne', 'geometryPickSurfaceOther'],
|
|
50
|
+
polysurface: ['geometryPickPolysurfaceOne', 'geometryPickPolysurfaceOther'],
|
|
51
|
+
extrusion: ['geometryPickExtrusionOne', 'geometryPickExtrusionOther'],
|
|
52
|
+
mesh: ['geometryPickMeshOne', 'geometryPickMeshOther'],
|
|
53
|
+
subd: ['geometryPickSubdOne', 'geometryPickSubdOther'],
|
|
54
|
+
block: ['geometryPickBlockOne', 'geometryPickBlockOther']
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const pickLabel = $derived.by(() => {
|
|
58
|
+
const [one, other] = kinds?.length === 1 ? KIND_LABELS[kinds[0]] : ANY_LABELS;
|
|
59
|
+
return t[atMost === 1 ? one : other];
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Rhino's command line prompts during the pick; the page keeps the button from being pressed
|
|
63
|
+
// twice and says where to look.
|
|
64
|
+
let picking = $state(false);
|
|
65
|
+
// The last pick or clear wins over what the host reported when the page loaded.
|
|
66
|
+
let local = $state<string | null | undefined>(undefined);
|
|
67
|
+
const shown = $derived(local !== undefined ? local : (summary ?? null));
|
|
68
|
+
|
|
69
|
+
$effect(() =>
|
|
70
|
+
watchSummary?.((held) => {
|
|
71
|
+
local = held;
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
async function pick(onPick: () => Promise<GeometryPickResult>) {
|
|
76
|
+
picking = true;
|
|
77
|
+
try {
|
|
78
|
+
const result = await onPick();
|
|
79
|
+
if (result.outcome === 'picked') local = result.summary;
|
|
80
|
+
else if (result.outcome === 'failed') onError?.(result.error);
|
|
81
|
+
} finally {
|
|
82
|
+
picking = false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// The field label points at inputId: the button where there is one, else an <output>, which
|
|
87
|
+
// unlike a <span> can be labelled.
|
|
88
|
+
const readout = $derived(onPick ? 'span' : 'output');
|
|
89
|
+
|
|
90
|
+
function clear(onClear: () => void) {
|
|
91
|
+
local = null;
|
|
92
|
+
onClear();
|
|
93
|
+
}
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<div class="gap-2 min-w-0 flex flex-wrap items-center">
|
|
97
|
+
{#if onPick}
|
|
98
|
+
<Button
|
|
99
|
+
id={inputId}
|
|
100
|
+
variant="outline"
|
|
101
|
+
size="sm"
|
|
102
|
+
onclick={() => pick(onPick)}
|
|
103
|
+
disabled={disabled || picking}
|
|
104
|
+
>
|
|
105
|
+
{shown ? t.geometryPickAgain : pickLabel}
|
|
106
|
+
</Button>
|
|
107
|
+
{/if}
|
|
108
|
+
{#if picking}
|
|
109
|
+
<span class="text-sm min-w-0 text-muted-foreground" role="status">{t.geometryPicking}</span>
|
|
110
|
+
{:else if shown}
|
|
111
|
+
<svelte:element
|
|
112
|
+
this={readout}
|
|
113
|
+
id={onPick ? undefined : inputId}
|
|
114
|
+
class="text-sm min-w-0 truncate text-foreground"
|
|
115
|
+
>
|
|
116
|
+
{shown}
|
|
117
|
+
</svelte:element>
|
|
118
|
+
{#if onClear}
|
|
119
|
+
<Button variant="ghost" size="sm" onclick={() => clear(onClear)} {disabled}>
|
|
120
|
+
{t.geometryClear}
|
|
121
|
+
</Button>
|
|
122
|
+
{/if}
|
|
123
|
+
{:else if !onPick}
|
|
124
|
+
<output id={inputId} class="text-sm min-w-0 text-muted-foreground"
|
|
125
|
+
>{t.geometryPickInPanel}</output
|
|
126
|
+
>
|
|
127
|
+
{/if}
|
|
128
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { GeometryPickResult, PickKind } from '../../../contexts/hostContext.svelte.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
inputId: string;
|
|
4
|
+
/** The kinds of object the input takes; one kind names the button after it. */
|
|
5
|
+
kinds?: readonly PickKind[];
|
|
6
|
+
/** 1 picks a single object. */
|
|
7
|
+
atMost?: number;
|
|
8
|
+
/** What the host reports the param holds, such as "2 curves"; absent until something is picked. */
|
|
9
|
+
summary?: string;
|
|
10
|
+
/** Absent where this page may not pick, such as a browser tab beside the Rhino panel. */
|
|
11
|
+
onPick?: () => Promise<GeometryPickResult>;
|
|
12
|
+
onClear?: () => void;
|
|
13
|
+
/** Subscribes to what the host holds after any page picks or clears; returns an unsubscribe. */
|
|
14
|
+
watchSummary?: (listener: (summary: string | null) => void) => () => void;
|
|
15
|
+
/** Shown when the pick fails; the host's own message. */
|
|
16
|
+
onError?: (message: string) => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
declare const GeometryInput: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type GeometryInput = ReturnType<typeof GeometryInput>;
|
|
21
|
+
export default GeometryInput;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { NumberWidgetConfig, SupportedTypes } from '@selvajs/schemas';
|
|
3
|
-
import { debounce } from '../../../utils/debounce';
|
|
4
|
-
import { Input } from '../../primitives/input';
|
|
5
|
-
import { Slider } from '../../primitives/slider';
|
|
6
|
-
import * as InputGroup from '../../primitives/input-group';
|
|
7
|
-
import { Separator } from '../../primitives/separator';
|
|
8
|
-
import * as Field from '../../primitives/field';
|
|
9
|
-
import { getLocaleContext } from '../../../i18n/localeContext.svelte';
|
|
10
|
-
import { formatMessage } from '../../../i18n/messages';
|
|
3
|
+
import { debounce } from '../../../utils/debounce.js';
|
|
4
|
+
import { Input } from '../../primitives/input/index.js';
|
|
5
|
+
import { Slider } from '../../primitives/slider/index.js';
|
|
6
|
+
import * as InputGroup from '../../primitives/input-group/index.js';
|
|
7
|
+
import { Separator } from '../../primitives/separator/index.js';
|
|
8
|
+
import * as Field from '../../primitives/field/index.js';
|
|
9
|
+
import { getLocaleContext } from '../../../i18n/localeContext.svelte.js';
|
|
10
|
+
import { formatMessage } from '../../../i18n/messages.js';
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
inputId: string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { GlyphSource } from '../../../schema/option-display.js';
|
|
3
|
+
import { cn } from '../../../utils.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
glyph: GlyphSource;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { glyph, class: className }: Props = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
{#if glyph.kind === 'icon'}
|
|
14
|
+
<!-- Lucide's stroke defaults; the path is bound as an attribute, never parsed as markup. -->
|
|
15
|
+
<svg
|
|
16
|
+
viewBox="0 0 24 24"
|
|
17
|
+
fill="none"
|
|
18
|
+
stroke="currentColor"
|
|
19
|
+
stroke-width="2"
|
|
20
|
+
stroke-linecap="round"
|
|
21
|
+
stroke-linejoin="round"
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
class={cn('size-4 shrink-0', className)}
|
|
24
|
+
>
|
|
25
|
+
<path d={glyph.d} />
|
|
26
|
+
</svg>
|
|
27
|
+
{:else}
|
|
28
|
+
<img src={glyph.src} alt="" class={cn('size-4 shrink-0 rounded-sm object-cover', className)} />
|
|
29
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GlyphSource } from '../../../schema/option-display.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
glyph: GlyphSource;
|
|
4
|
+
class?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const OptionGlyph: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type OptionGlyph = ReturnType<typeof OptionGlyph>;
|
|
8
|
+
export default OptionGlyph;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
|
|
3
|
+
import * as ToggleGroup from '../../primitives/toggle-group/index.js';
|
|
4
|
+
import { optionGlyph } from '../../../schema/option-display.js';
|
|
5
|
+
import OptionGlyph from './OptionGlyph.svelte';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
labelId: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
config: DropdownWidgetConfig;
|
|
11
|
+
assets?: UISchema['assets'];
|
|
12
|
+
onChange: (value: SupportedTypes) => void;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { labelId, value, config, assets, onChange, disabled = false }: Props = $props();
|
|
17
|
+
|
|
18
|
+
const options = $derived(Object.entries(config.options ?? {}));
|
|
19
|
+
const hasIcons = $derived(
|
|
20
|
+
options.some(([name]) => optionGlyph(config.optionMedia?.[name], assets))
|
|
21
|
+
);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<ToggleGroup.Root
|
|
25
|
+
type="single"
|
|
26
|
+
variant="outline"
|
|
27
|
+
spacing={0}
|
|
28
|
+
size={hasIcons ? 'stacked' : 'default'}
|
|
29
|
+
class="w-full"
|
|
30
|
+
aria-labelledby={labelId}
|
|
31
|
+
value={value ?? ''}
|
|
32
|
+
onValueChange={(next) => {
|
|
33
|
+
// A single-select group emits '' when the active item is clicked again; keep the selection.
|
|
34
|
+
if (next) onChange(next);
|
|
35
|
+
}}
|
|
36
|
+
{disabled}
|
|
37
|
+
>
|
|
38
|
+
{#each options as [name, expr] (name)}
|
|
39
|
+
{@const glyph = optionGlyph(config.optionMedia?.[name], assets)}
|
|
40
|
+
<ToggleGroup.Item value={expr ?? name} class="min-w-0 flex-1" title={name}>
|
|
41
|
+
{#if glyph}<OptionGlyph {glyph} />{/if}
|
|
42
|
+
<span class="max-w-full truncate">{name}</span>
|
|
43
|
+
</ToggleGroup.Item>
|
|
44
|
+
{/each}
|
|
45
|
+
</ToggleGroup.Root>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
|
|
2
|
+
interface Props {
|
|
3
|
+
labelId: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
config: DropdownWidgetConfig;
|
|
6
|
+
assets?: UISchema['assets'];
|
|
7
|
+
onChange: (value: SupportedTypes) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const SegmentedInput: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type SegmentedInput = ReturnType<typeof SegmentedInput>;
|
|
12
|
+
export default SegmentedInput;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { TextWidgetConfig, SupportedTypes } from '@selvajs/schemas';
|
|
3
|
-
import { debounce } from '../../../utils/debounce';
|
|
4
|
-
import { Input } from '../../primitives/input';
|
|
5
|
-
import * as Field from '../../primitives/field';
|
|
6
|
-
import { getLocaleContext } from '../../../i18n/localeContext.svelte';
|
|
7
|
-
import { formatMessage } from '../../../i18n/messages';
|
|
3
|
+
import { debounce } from '../../../utils/debounce.js';
|
|
4
|
+
import { Input } from '../../primitives/input/index.js';
|
|
5
|
+
import * as Field from '../../primitives/field/index.js';
|
|
6
|
+
import { getLocaleContext } from '../../../i18n/localeContext.svelte.js';
|
|
7
|
+
import { formatMessage } from '../../../i18n/messages.js';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
10
|
inputId: string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
|
|
3
|
+
import { optionGlyph } from '../../../schema/option-display.js';
|
|
4
|
+
import OptionGlyph from './OptionGlyph.svelte';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
labelId: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
config: DropdownWidgetConfig;
|
|
10
|
+
assets?: UISchema['assets'];
|
|
11
|
+
onChange: (value: SupportedTypes) => void;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { labelId, value, config, assets, onChange, disabled = false }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const options = $derived(
|
|
18
|
+
Object.entries(config.options ?? {}).map(([name, expr]) => ({ name, value: expr ?? name }))
|
|
19
|
+
);
|
|
20
|
+
// With nothing selected the first tile takes focus, so the group is still reachable by Tab.
|
|
21
|
+
const focusIndex = $derived(
|
|
22
|
+
Math.max(
|
|
23
|
+
0,
|
|
24
|
+
options.findIndex((o) => o.value === value)
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let tiles: HTMLButtonElement[] = $state([]);
|
|
29
|
+
|
|
30
|
+
function onKeydown(event: KeyboardEvent, index: number) {
|
|
31
|
+
const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[event.key];
|
|
32
|
+
if (!step) return;
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
const next = (index + step + options.length) % options.length;
|
|
35
|
+
onChange(options[next].value);
|
|
36
|
+
tiles[next]?.focus();
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div role="radiogroup" aria-labelledby={labelId} class="gap-2 tile-grid grid">
|
|
41
|
+
{#each options as option, index (option.name)}
|
|
42
|
+
{@const glyph = optionGlyph(config.optionMedia?.[option.name], assets)}
|
|
43
|
+
{@const selected = option.value === value}
|
|
44
|
+
<button
|
|
45
|
+
bind:this={tiles[index]}
|
|
46
|
+
type="button"
|
|
47
|
+
role="radio"
|
|
48
|
+
title={option.name}
|
|
49
|
+
aria-checked={selected}
|
|
50
|
+
tabindex={index === focusIndex ? 0 : -1}
|
|
51
|
+
{disabled}
|
|
52
|
+
onclick={() => onChange(option.value)}
|
|
53
|
+
onkeydown={(e) => onKeydown(e, index)}
|
|
54
|
+
class="gap-1.5 p-1.5 min-w-0 flex flex-col rounded-lg border text-left transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 {selected
|
|
55
|
+
? 'border-primary bg-primary/10 ring-1 ring-primary'
|
|
56
|
+
: 'border-input hover:bg-hover'}"
|
|
57
|
+
>
|
|
58
|
+
<span
|
|
59
|
+
class="flex aspect-square w-full items-center justify-center overflow-hidden rounded-md bg-muted {selected
|
|
60
|
+
? 'text-foreground'
|
|
61
|
+
: 'text-muted-foreground'}"
|
|
62
|
+
>
|
|
63
|
+
{#if glyph?.kind === 'image'}
|
|
64
|
+
<OptionGlyph {glyph} class="size-full" />
|
|
65
|
+
{:else if glyph}
|
|
66
|
+
<OptionGlyph {glyph} class="size-7" />
|
|
67
|
+
{:else}
|
|
68
|
+
<span class="text-lg font-medium" aria-hidden="true">{option.name.charAt(0)}</span>
|
|
69
|
+
{/if}
|
|
70
|
+
</span>
|
|
71
|
+
<span class="px-0.5 text-xs leading-tight line-clamp-2" class:font-medium={selected}>
|
|
72
|
+
{option.name}
|
|
73
|
+
</span>
|
|
74
|
+
</button>
|
|
75
|
+
{/each}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
/* Two or three tiles a row as the panel narrows; a fixed count shrinks them to unreadable. */
|
|
80
|
+
.tile-grid {
|
|
81
|
+
grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
|
|
2
|
+
interface Props {
|
|
3
|
+
labelId: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
config: DropdownWidgetConfig;
|
|
6
|
+
assets?: UISchema['assets'];
|
|
7
|
+
onChange: (value: SupportedTypes) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const TileInput: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type TileInput = ReturnType<typeof TileInput>;
|
|
12
|
+
export default TileInput;
|
|
@@ -3,5 +3,8 @@ export { default as ChecklistInput } from './ChecklistInput.svelte';
|
|
|
3
3
|
export { default as ColorInput } from './ColorInput.svelte';
|
|
4
4
|
export { default as DropdownInput } from './DropdownInput.svelte';
|
|
5
5
|
export { default as FileInput } from './FileInput.svelte';
|
|
6
|
+
export { default as GeometryInput } from './GeometryInput.svelte';
|
|
6
7
|
export { default as NumberInput } from './NumberInput.svelte';
|
|
8
|
+
export { default as SegmentedInput } from './SegmentedInput.svelte';
|
|
7
9
|
export { default as TextInput } from './TextInput.svelte';
|
|
10
|
+
export { default as TileInput } from './TileInput.svelte';
|
|
@@ -3,5 +3,8 @@ export { default as ChecklistInput } from './ChecklistInput.svelte';
|
|
|
3
3
|
export { default as ColorInput } from './ColorInput.svelte';
|
|
4
4
|
export { default as DropdownInput } from './DropdownInput.svelte';
|
|
5
5
|
export { default as FileInput } from './FileInput.svelte';
|
|
6
|
+
export { default as GeometryInput } from './GeometryInput.svelte';
|
|
6
7
|
export { default as NumberInput } from './NumberInput.svelte';
|
|
8
|
+
export { default as SegmentedInput } from './SegmentedInput.svelte';
|
|
7
9
|
export { default as TextInput } from './TextInput.svelte';
|
|
10
|
+
export { default as TileInput } from './TileInput.svelte';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack, type Snippet } from 'svelte';
|
|
3
3
|
import { Button } from './button';
|
|
4
|
-
import { Zap,
|
|
4
|
+
import { Zap, LoaderCircle, Play } from '@lucide/svelte';
|
|
5
5
|
import { getLocaleContext } from '../../i18n/localeContext.svelte';
|
|
6
6
|
|
|
7
7
|
const locale = getLocaleContext();
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
});
|
|
39
39
|
</script>
|
|
40
40
|
|
|
41
|
-
<div class="bottom-0 mt-3 pb-3 pt-2 backdrop-blur-sm px-2 sticky border-t border-border
|
|
41
|
+
<div class="bottom-0 mt-3 pb-3 pt-2 backdrop-blur-sm px-2 sticky border-t border-border">
|
|
42
42
|
<span class="sr-only" role="status" aria-live="polite">{announcement}</span>
|
|
43
43
|
<div class="gap-2 flex">
|
|
44
44
|
<Button
|
|
@@ -52,8 +52,14 @@
|
|
|
52
52
|
{!hasPendingChanges && !isSolving ? 'text-muted-foreground' : ''}"
|
|
53
53
|
>
|
|
54
54
|
{#if isSolving}
|
|
55
|
-
<
|
|
55
|
+
<LoaderCircle class="h-4 w-4 animate-spin" />
|
|
56
56
|
{t.solvingEllipsis}
|
|
57
|
+
<kbd
|
|
58
|
+
class="px-1 rounded-sm border border-current/30 font-sans text-2xs opacity-70"
|
|
59
|
+
title={t.solveMessagesEscHint}
|
|
60
|
+
>
|
|
61
|
+
Esc
|
|
62
|
+
</kbd>
|
|
57
63
|
{:else if hasNeverSolved}
|
|
58
64
|
<Play class="h-4 w-4" />
|
|
59
65
|
{t.pressToCalculate}
|
|
@@ -61,7 +67,7 @@
|
|
|
61
67
|
<Zap class="h-4 w-4" />
|
|
62
68
|
{t.calculate}
|
|
63
69
|
{:else}
|
|
64
|
-
<
|
|
70
|
+
<span class="size-1.5 shrink-0 rounded-full bg-success" aria-hidden="true"></span>
|
|
65
71
|
{t.upToDate}
|
|
66
72
|
{/if}
|
|
67
73
|
</Button>
|