@morscherlab/mint-sdk 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +326 -0
- package/dist/__stories__/experiment-helpers.d.ts +25 -0
- package/dist/__tests__/components/AppLayout.test.d.ts +1 -0
- package/dist/__tests__/components/AppSidebar.test.d.ts +1 -0
- package/dist/__tests__/components/AppTopBar.test.d.ts +1 -0
- package/dist/__tests__/components/BaseInput.test.d.ts +1 -0
- package/dist/__tests__/components/BasePill.test.d.ts +1 -0
- package/dist/__tests__/components/Calendar.test.d.ts +1 -0
- package/dist/__tests__/components/CollapsibleCard.test.d.ts +1 -0
- package/dist/__tests__/components/DataFrame.test.d.ts +1 -0
- package/dist/__tests__/components/DropdownButton.test.d.ts +1 -0
- package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +1 -0
- package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
- package/dist/__tests__/composables/useAuth.test.d.ts +1 -0
- package/dist/__tests__/composables/useAutoGroup.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentData.test.d.ts +13 -0
- package/dist/__tests__/composables/useExperimentSave.test.d.ts +1 -0
- package/dist/__tests__/composables/useForm.test.d.ts +1 -0
- package/dist/__tests__/composables/useFormBuilder.test.d.ts +1 -0
- package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
- package/dist/__tests__/composables/usePluginApi.test.d.ts +13 -0
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +14 -0
- package/dist/__tests__/utils/color.test.d.ts +1 -0
- package/dist/auth-BYmxZdJl.js +297 -0
- package/dist/auth-BYmxZdJl.js.map +1 -0
- package/dist/components/AlertBox.vue.d.ts +34 -0
- package/dist/components/AppAvatarMenu.vue.d.ts +58 -0
- package/dist/components/AppContainer.vue.d.ts +28 -0
- package/dist/components/AppLayout.vue.d.ts +31 -0
- package/dist/components/AppPageSelector.vue.d.ts +43 -0
- package/dist/components/AppPillNav.vue.d.ts +11 -0
- package/dist/components/AppPluginSwitcher.vue.d.ts +38 -0
- package/dist/components/AppSidebar.vue.d.ts +47 -0
- package/dist/components/AppTopBar.vue.d.ts +111 -0
- package/dist/components/AuditTrail.vue.d.ts +38 -0
- package/dist/components/AutoGroupModal.vue.d.ts +124 -0
- package/dist/components/Avatar.vue.d.ts +14 -0
- package/dist/components/BaseButton.vue.d.ts +37 -0
- package/dist/components/BaseCheckbox.vue.d.ts +17 -0
- package/dist/components/BaseInput.vue.d.ts +34 -0
- package/dist/components/BaseModal.vue.d.ts +46 -0
- package/dist/components/BasePill.vue.d.ts +57 -0
- package/dist/components/BaseRadioGroup.vue.d.ts +21 -0
- package/dist/components/BaseSelect.vue.d.ts +20 -0
- package/dist/components/BaseSlider.vue.d.ts +22 -0
- package/dist/components/BaseTabs.vue.d.ts +14 -0
- package/dist/components/BaseTextarea.vue.d.ts +30 -0
- package/dist/components/BaseToggle.vue.d.ts +19 -0
- package/dist/components/BatchProgressList.vue.d.ts +43 -0
- package/dist/components/Breadcrumb.vue.d.ts +33 -0
- package/dist/components/Calendar.vue.d.ts +107 -0
- package/dist/components/ChartContainer.vue.d.ts +31 -0
- package/dist/components/ChemicalFormula.vue.d.ts +8 -0
- package/dist/components/CollapsibleCard.vue.d.ts +41 -0
- package/dist/components/ColorSlider.vue.d.ts +34 -0
- package/dist/components/ConcentrationInput.vue.d.ts +25 -0
- package/dist/components/ConfirmDialog.vue.d.ts +42 -0
- package/dist/components/DataFrame.vue.d.ts +107 -0
- package/dist/components/DatePicker.vue.d.ts +25 -0
- package/dist/components/DateTimePicker.vue.d.ts +30 -0
- package/dist/components/Divider.vue.d.ts +14 -0
- package/dist/components/DoseCalculator.vue.d.ts +19 -0
- package/dist/components/DropdownButton.vue.d.ts +47 -0
- package/dist/components/EmptyState.vue.d.ts +36 -0
- package/dist/components/ExperimentCodeBadge.vue.d.ts +14 -0
- package/dist/components/ExperimentDataViewer.vue.d.ts +29 -0
- package/dist/components/ExperimentPopover.vue.d.ts +32 -0
- package/dist/components/ExperimentSelectorModal.vue.d.ts +28 -0
- package/dist/components/ExperimentTimeline.vue.d.ts +44 -0
- package/dist/components/FileUploader.vue.d.ts +40 -0
- package/dist/components/FitPanel.vue.d.ts +46 -0
- package/dist/components/FormActions.vue.d.ts +33 -0
- package/dist/components/FormBuilder.vue.d.ts +287 -0
- package/dist/components/FormField.vue.d.ts +28 -0
- package/dist/components/FormFieldRenderer.vue.d.ts +31 -0
- package/dist/components/FormSection.vue.d.ts +43 -0
- package/dist/components/FormulaInput.vue.d.ts +25 -0
- package/dist/components/GroupAssigner.vue.d.ts +25 -0
- package/dist/components/GroupingModal.vue.d.ts +12 -0
- package/dist/components/IconButton.vue.d.ts +34 -0
- package/dist/components/LoadingSpinner.vue.d.ts +12 -0
- package/dist/components/MoleculeInput.vue.d.ts +27 -0
- package/dist/components/MultiSelect.vue.d.ts +19 -0
- package/dist/components/NumberInput.vue.d.ts +22 -0
- package/dist/components/PlateMapEditor.vue.d.ts +50 -0
- package/dist/components/ProgressBar.vue.d.ts +23 -0
- package/dist/components/ProtocolStepEditor.vue.d.ts +24 -0
- package/dist/components/RackEditor.vue.d.ts +40 -0
- package/dist/components/ReagentEditor.vue.d.ts +30 -0
- package/dist/components/ReagentList.vue.d.ts +32 -0
- package/dist/components/ResourceCard.vue.d.ts +50 -0
- package/dist/components/SampleHierarchyTree.vue.d.ts +26 -0
- package/dist/components/SampleLegend.vue.d.ts +32 -0
- package/dist/components/SampleSelector.vue.d.ts +29 -0
- package/dist/components/ScheduleCalendar.vue.d.ts +110 -0
- package/dist/components/ScientificNumber.vue.d.ts +14 -0
- package/dist/components/SegmentedControl.vue.d.ts +20 -0
- package/dist/components/SequenceInput.vue.d.ts +54 -0
- package/dist/components/SettingsButton.vue.d.ts +30 -0
- package/dist/components/SettingsModal.vue.d.ts +36 -0
- package/dist/components/Skeleton.vue.d.ts +11 -0
- package/dist/components/StatusIndicator.vue.d.ts +13 -0
- package/dist/components/StepWizard.vue.d.ts +65 -0
- package/dist/components/TagsInput.vue.d.ts +39 -0
- package/dist/components/ThemeToggle.vue.d.ts +7 -0
- package/dist/components/TimePicker.vue.d.ts +29 -0
- package/dist/components/TimeRangeInput.vue.d.ts +27 -0
- package/dist/components/ToastNotification.vue.d.ts +2 -0
- package/dist/components/Tooltip.vue.d.ts +35 -0
- package/dist/components/UnitInput.vue.d.ts +39 -0
- package/dist/components/WellEditPopup.vue.d.ts +25 -0
- package/dist/components/WellPlate.vue.d.ts +73 -0
- package/dist/components/index.d.ts +87 -0
- package/dist/components/index.js +3 -0
- package/dist/components-CKf-UpGi.js +15089 -0
- package/dist/components-CKf-UpGi.js.map +1 -0
- package/dist/composables/experiment-utils.d.ts +8 -0
- package/dist/composables/formBuilderRegistry.d.ts +13 -0
- package/dist/composables/index.d.ts +28 -0
- package/dist/composables/index.js +3 -0
- package/dist/composables/useApi.d.ts +20 -0
- package/dist/composables/useAppExperiment.d.ts +37 -0
- package/dist/composables/useAsync.d.ts +128 -0
- package/dist/composables/useAuth.d.ts +47 -0
- package/dist/composables/useAutoGroup.d.ts +106 -0
- package/dist/composables/useChemicalFormula.d.ts +21 -0
- package/dist/composables/useConcentrationUnits.d.ts +29 -0
- package/dist/composables/useDoseCalculator.d.ts +58 -0
- package/dist/composables/useExperimentData.d.ts +18 -0
- package/dist/composables/useExperimentSave.d.ts +36 -0
- package/dist/composables/useExperimentSelector.d.ts +30 -0
- package/dist/composables/useForm.d.ts +92 -0
- package/dist/composables/useFormBuilder.d.ts +24 -0
- package/dist/composables/usePasskey.d.ts +10 -0
- package/dist/composables/usePlatformContext.d.ts +131 -0
- package/dist/composables/usePluginApi.d.ts +29 -0
- package/dist/composables/usePluginConfig.d.ts +13 -0
- package/dist/composables/useProtocolTemplates.d.ts +44 -0
- package/dist/composables/useRackEditor.d.ts +31 -0
- package/dist/composables/useReagentSeries.d.ts +23 -0
- package/dist/composables/useScheduleDrag.d.ts +78 -0
- package/dist/composables/useSequenceUtils.d.ts +14 -0
- package/dist/composables/useTheme.d.ts +8 -0
- package/dist/composables/useTimeUtils.d.ts +29 -0
- package/dist/composables/useToast.d.ts +22 -0
- package/dist/composables/useWellPlateEditor.d.ts +33 -0
- package/dist/composables-D0QfFzq1.js +805 -0
- package/dist/composables-D0QfFzq1.js.map +1 -0
- package/dist/histoire.setup.d.ts +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/install.d.ts +16 -0
- package/dist/install.js +23 -0
- package/dist/install.js.map +1 -0
- package/dist/stores/auth.d.ts +146 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/index.js +2 -0
- package/dist/stores/settings.d.ts +75 -0
- package/dist/styles.css +29728 -0
- package/dist/tailwind.preset.d.ts +58 -0
- package/dist/tailwind.preset.js +66 -0
- package/dist/tailwind.preset.js.map +1 -0
- package/dist/types/auth.d.ts +42 -0
- package/dist/types/auto-group.d.ts +34 -0
- package/dist/types/components.d.ts +528 -0
- package/dist/types/form-builder.d.ts +167 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +0 -0
- package/dist/types/platform.d.ts +75 -0
- package/dist/useScheduleDrag-DAJueTbK.js +7181 -0
- package/dist/useScheduleDrag-DAJueTbK.js.map +1 -0
- package/dist/utils/color.d.ts +24 -0
- package/package.json +114 -0
- package/src/__stories__/experiment-helpers.ts +83 -0
- package/src/__tests__/components/AppLayout.test.ts +163 -0
- package/src/__tests__/components/AppSidebar.test.ts +292 -0
- package/src/__tests__/components/AppTopBar.test.ts +683 -0
- package/src/__tests__/components/BaseInput.test.ts +99 -0
- package/src/__tests__/components/BasePill.test.ts +291 -0
- package/src/__tests__/components/Calendar.test.ts +566 -0
- package/src/__tests__/components/CollapsibleCard.test.ts +524 -0
- package/src/__tests__/components/DataFrame.test.ts +767 -0
- package/src/__tests__/components/DropdownButton.test.ts +471 -0
- package/src/__tests__/composables/formBuilderRegistry.test.ts +187 -0
- package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
- package/src/__tests__/composables/useAuth.test.ts +188 -0
- package/src/__tests__/composables/useAutoGroup.test.ts +860 -0
- package/src/__tests__/composables/useExperimentData.test.ts +127 -0
- package/src/__tests__/composables/useExperimentSave.test.ts +347 -0
- package/src/__tests__/composables/useForm.test.ts +205 -0
- package/src/__tests__/composables/useFormBuilder.test.ts +917 -0
- package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
- package/src/__tests__/composables/usePluginApi.test.ts +81 -0
- package/src/__tests__/composables/usePluginConfig.test.ts +176 -0
- package/src/__tests__/utils/color.test.ts +96 -0
- package/src/components/AlertBox.story.vue +204 -0
- package/src/components/AlertBox.vue +88 -0
- package/src/components/AppAvatarMenu.story.vue +155 -0
- package/src/components/AppAvatarMenu.vue +184 -0
- package/src/components/AppContainer.story.vue +104 -0
- package/src/components/AppContainer.vue +34 -0
- package/src/components/AppLayout.story.vue +292 -0
- package/src/components/AppLayout.vue +75 -0
- package/src/components/AppPageSelector.vue +159 -0
- package/src/components/AppPillNav.vue +66 -0
- package/src/components/AppPluginSwitcher.vue +241 -0
- package/src/components/AppSidebar.story.vue +309 -0
- package/src/components/AppSidebar.vue +119 -0
- package/src/components/AppTopBar.story.vue +304 -0
- package/src/components/AppTopBar.vue +661 -0
- package/src/components/AuditTrail.story.vue +163 -0
- package/src/components/AuditTrail.vue +151 -0
- package/src/components/AutoGroupModal.story.vue +273 -0
- package/src/components/AutoGroupModal.vue +566 -0
- package/src/components/Avatar.story.vue +115 -0
- package/src/components/Avatar.vue +79 -0
- package/src/components/BaseButton.story.vue +96 -0
- package/src/components/BaseButton.vue +73 -0
- package/src/components/BaseCheckbox.story.vue +73 -0
- package/src/components/BaseCheckbox.vue +69 -0
- package/src/components/BaseInput.story.vue +98 -0
- package/src/components/BaseInput.vue +74 -0
- package/src/components/BaseModal.story.vue +237 -0
- package/src/components/BaseModal.vue +182 -0
- package/src/components/BasePill.story.vue +142 -0
- package/src/components/BasePill.vue +89 -0
- package/src/components/BaseRadioGroup.story.vue +145 -0
- package/src/components/BaseRadioGroup.vue +124 -0
- package/src/components/BaseSelect.story.vue +120 -0
- package/src/components/BaseSelect.vue +71 -0
- package/src/components/BaseSlider.story.vue +122 -0
- package/src/components/BaseSlider.vue +126 -0
- package/src/components/BaseTabs.story.vue +127 -0
- package/src/components/BaseTabs.vue +59 -0
- package/src/components/BaseTextarea.story.vue +91 -0
- package/src/components/BaseTextarea.vue +62 -0
- package/src/components/BaseToggle.story.vue +81 -0
- package/src/components/BaseToggle.vue +76 -0
- package/src/components/BatchProgressList.story.vue +92 -0
- package/src/components/BatchProgressList.vue +184 -0
- package/src/components/Breadcrumb.story.vue +106 -0
- package/src/components/Breadcrumb.vue +75 -0
- package/src/components/Calendar.story.vue +106 -0
- package/src/components/Calendar.vue +363 -0
- package/src/components/ChartContainer.story.vue +113 -0
- package/src/components/ChartContainer.vue +64 -0
- package/src/components/ChemicalFormula.story.vue +102 -0
- package/src/components/ChemicalFormula.vue +39 -0
- package/src/components/CollapsibleCard.story.vue +135 -0
- package/src/components/CollapsibleCard.vue +167 -0
- package/src/components/ColorSlider.story.vue +120 -0
- package/src/components/ColorSlider.vue +164 -0
- package/src/components/ConcentrationInput.story.vue +77 -0
- package/src/components/ConcentrationInput.vue +185 -0
- package/src/components/ConfirmDialog.story.vue +248 -0
- package/src/components/ConfirmDialog.vue +93 -0
- package/src/components/DataFrame.story.vue +148 -0
- package/src/components/DataFrame.vue +419 -0
- package/src/components/DatePicker.story.vue +119 -0
- package/src/components/DatePicker.vue +330 -0
- package/src/components/DateTimePicker.story.vue +112 -0
- package/src/components/DateTimePicker.vue +392 -0
- package/src/components/Divider.story.vue +80 -0
- package/src/components/Divider.vue +49 -0
- package/src/components/DoseCalculator.story.vue +68 -0
- package/src/components/DoseCalculator.vue +476 -0
- package/src/components/DropdownButton.story.vue +102 -0
- package/src/components/DropdownButton.vue +181 -0
- package/src/components/EmptyState.story.vue +135 -0
- package/src/components/EmptyState.vue +69 -0
- package/src/components/ExperimentCodeBadge.story.vue +77 -0
- package/src/components/ExperimentCodeBadge.vue +64 -0
- package/src/components/ExperimentDataViewer.story.vue +174 -0
- package/src/components/ExperimentDataViewer.vue +288 -0
- package/src/components/ExperimentPopover.story.vue +384 -0
- package/src/components/ExperimentPopover.vue +241 -0
- package/src/components/ExperimentSelectorModal.story.vue +391 -0
- package/src/components/ExperimentSelectorModal.vue +387 -0
- package/src/components/ExperimentTimeline.story.vue +161 -0
- package/src/components/ExperimentTimeline.vue +382 -0
- package/src/components/FileUploader.story.vue +107 -0
- package/src/components/FileUploader.vue +386 -0
- package/src/components/FitPanel.story.vue +125 -0
- package/src/components/FitPanel.vue +120 -0
- package/src/components/FormActions.vue +92 -0
- package/src/components/FormBuilder.vue +214 -0
- package/src/components/FormField.story.vue +132 -0
- package/src/components/FormField.vue +59 -0
- package/src/components/FormFieldRenderer.vue +58 -0
- package/src/components/FormSection.vue +90 -0
- package/src/components/FormulaInput.story.vue +96 -0
- package/src/components/FormulaInput.vue +125 -0
- package/src/components/GroupAssigner.story.vue +83 -0
- package/src/components/GroupAssigner.vue +284 -0
- package/src/components/GroupingModal.story.vue +52 -0
- package/src/components/GroupingModal.vue +422 -0
- package/src/components/IconButton.story.vue +135 -0
- package/src/components/IconButton.vue +73 -0
- package/src/components/LoadingSpinner.story.vue +70 -0
- package/src/components/LoadingSpinner.vue +50 -0
- package/src/components/MoleculeInput.story.vue +66 -0
- package/src/components/MoleculeInput.vue +426 -0
- package/src/components/MultiSelect.story.vue +132 -0
- package/src/components/MultiSelect.vue +118 -0
- package/src/components/NumberInput.story.vue +122 -0
- package/src/components/NumberInput.vue +160 -0
- package/src/components/PlateMapEditor.story.vue +92 -0
- package/src/components/PlateMapEditor.vue +513 -0
- package/src/components/ProgressBar.story.vue +148 -0
- package/src/components/ProgressBar.vue +114 -0
- package/src/components/ProtocolStepEditor.story.vue +69 -0
- package/src/components/ProtocolStepEditor.vue +522 -0
- package/src/components/RackEditor.story.vue +100 -0
- package/src/components/RackEditor.vue +371 -0
- package/src/components/ReagentEditor.story.vue +153 -0
- package/src/components/ReagentEditor.vue +418 -0
- package/src/components/ReagentList.story.vue +137 -0
- package/src/components/ReagentList.vue +463 -0
- package/src/components/ResourceCard.story.vue +150 -0
- package/src/components/ResourceCard.vue +161 -0
- package/src/components/SampleHierarchyTree.story.vue +161 -0
- package/src/components/SampleHierarchyTree.vue +256 -0
- package/src/components/SampleLegend.story.vue +91 -0
- package/src/components/SampleLegend.vue +119 -0
- package/src/components/SampleSelector.story.vue +111 -0
- package/src/components/SampleSelector.vue +1033 -0
- package/src/components/ScheduleCalendar.story.vue +195 -0
- package/src/components/ScheduleCalendar.vue +569 -0
- package/src/components/ScientificNumber.story.vue +127 -0
- package/src/components/ScientificNumber.vue +197 -0
- package/src/components/SegmentedControl.story.vue +132 -0
- package/src/components/SegmentedControl.vue +79 -0
- package/src/components/SequenceInput.story.vue +119 -0
- package/src/components/SequenceInput.vue +209 -0
- package/src/components/SettingsButton.story.vue +58 -0
- package/src/components/SettingsButton.vue +76 -0
- package/src/components/SettingsModal.story.vue +145 -0
- package/src/components/SettingsModal.vue +146 -0
- package/src/components/Skeleton.story.vue +141 -0
- package/src/components/Skeleton.vue +74 -0
- package/src/components/StatusIndicator.story.vue +99 -0
- package/src/components/StatusIndicator.vue +40 -0
- package/src/components/StepWizard.story.vue +155 -0
- package/src/components/StepWizard.vue +223 -0
- package/src/components/TagsInput.story.vue +155 -0
- package/src/components/TagsInput.vue +265 -0
- package/src/components/ThemeToggle.story.vue +36 -0
- package/src/components/ThemeToggle.vue +54 -0
- package/src/components/TimePicker.story.vue +96 -0
- package/src/components/TimePicker.vue +273 -0
- package/src/components/TimeRangeInput.story.vue +104 -0
- package/src/components/TimeRangeInput.vue +122 -0
- package/src/components/ToastNotification.story.vue +157 -0
- package/src/components/ToastNotification.vue +62 -0
- package/src/components/Tooltip.story.vue +138 -0
- package/src/components/Tooltip.vue +119 -0
- package/src/components/UnitInput.story.vue +194 -0
- package/src/components/UnitInput.vue +213 -0
- package/src/components/WellEditPopup.vue +234 -0
- package/src/components/WellPlate.story.vue +282 -0
- package/src/components/WellPlate.vue +830 -0
- package/src/components/index.ts +118 -0
- package/src/composables/experiment-utils.ts +57 -0
- package/src/composables/formBuilderRegistry.ts +79 -0
- package/src/composables/index.ts +140 -0
- package/src/composables/useApi.ts +167 -0
- package/src/composables/useAppExperiment.ts +159 -0
- package/src/composables/useAsync.ts +323 -0
- package/src/composables/useAuth.ts +445 -0
- package/src/composables/useAutoGroup.ts +641 -0
- package/src/composables/useChemicalFormula.ts +275 -0
- package/src/composables/useConcentrationUnits.ts +246 -0
- package/src/composables/useDoseCalculator.ts +370 -0
- package/src/composables/useExperimentData.ts +86 -0
- package/src/composables/useExperimentSave.ts +192 -0
- package/src/composables/useExperimentSelector.ts +292 -0
- package/src/composables/useForm.ts +416 -0
- package/src/composables/useFormBuilder.ts +383 -0
- package/src/composables/usePasskey.ts +216 -0
- package/src/composables/usePlatformContext.ts +299 -0
- package/src/composables/usePluginApi.ts +39 -0
- package/src/composables/usePluginConfig.ts +93 -0
- package/src/composables/useProtocolTemplates.ts +518 -0
- package/src/composables/useRackEditor.ts +222 -0
- package/src/composables/useReagentSeries.ts +91 -0
- package/src/composables/useScheduleDrag.ts +245 -0
- package/src/composables/useSequenceUtils.ts +105 -0
- package/src/composables/useTheme.ts +58 -0
- package/src/composables/useTimeUtils.ts +131 -0
- package/src/composables/useToast.ts +40 -0
- package/src/composables/useWellPlateEditor.ts +421 -0
- package/src/histoire.setup.ts +17 -0
- package/src/index.ts +367 -0
- package/src/install.ts +32 -0
- package/src/stores/auth.ts +152 -0
- package/src/stores/index.ts +2 -0
- package/src/stores/settings.ts +218 -0
- package/src/styles/components/alert-box.css +150 -0
- package/src/styles/components/app-avatar-menu.css +155 -0
- package/src/styles/components/app-container.css +33 -0
- package/src/styles/components/app-layout.css +98 -0
- package/src/styles/components/app-page-selector.css +191 -0
- package/src/styles/components/app-pill-nav.css +57 -0
- package/src/styles/components/app-plugin-switcher.css +209 -0
- package/src/styles/components/app-sidebar.css +145 -0
- package/src/styles/components/app-top-bar.css +492 -0
- package/src/styles/components/audit-trail.css +143 -0
- package/src/styles/components/auto-group-modal.css +644 -0
- package/src/styles/components/avatar.css +73 -0
- package/src/styles/components/batch-progress-list.css +196 -0
- package/src/styles/components/breadcrumb.css +64 -0
- package/src/styles/components/button.css +188 -0
- package/src/styles/components/calendar.css +192 -0
- package/src/styles/components/chart-container.css +69 -0
- package/src/styles/components/checkbox.css +123 -0
- package/src/styles/components/chemical-formula.css +46 -0
- package/src/styles/components/collapsible-card.css +253 -0
- package/src/styles/components/color-slider.css +110 -0
- package/src/styles/components/concentration-input.css +156 -0
- package/src/styles/components/confirm-dialog.css +183 -0
- package/src/styles/components/dataframe.css +382 -0
- package/src/styles/components/date-picker.css +243 -0
- package/src/styles/components/datetime-picker.css +229 -0
- package/src/styles/components/divider.css +63 -0
- package/src/styles/components/dose-calculator.css +301 -0
- package/src/styles/components/dropdown-button.css +280 -0
- package/src/styles/components/empty-state.css +151 -0
- package/src/styles/components/experiment-code-badge.css +33 -0
- package/src/styles/components/experiment-data-viewer.css +138 -0
- package/src/styles/components/experiment-popover.css +562 -0
- package/src/styles/components/experiment-selector-modal.css +285 -0
- package/src/styles/components/experiment-timeline.css +529 -0
- package/src/styles/components/file-uploader.css +310 -0
- package/src/styles/components/fit-panel.css +67 -0
- package/src/styles/components/form-builder.css +69 -0
- package/src/styles/components/form-field.css +48 -0
- package/src/styles/components/formula-input.css +103 -0
- package/src/styles/components/group-assigner.css +200 -0
- package/src/styles/components/grouping-modal.css +323 -0
- package/src/styles/components/icon-button.css +192 -0
- package/src/styles/components/input.css +66 -0
- package/src/styles/components/loading-spinner.css +67 -0
- package/src/styles/components/modal.css +350 -0
- package/src/styles/components/molecule-input.css +186 -0
- package/src/styles/components/multi-select.css +131 -0
- package/src/styles/components/number-input.css +199 -0
- package/src/styles/components/pill.css +188 -0
- package/src/styles/components/plate-map-editor.css +464 -0
- package/src/styles/components/progress-bar.css +133 -0
- package/src/styles/components/protocol-step-editor.css +449 -0
- package/src/styles/components/rack-editor.css +265 -0
- package/src/styles/components/radio-group.css +240 -0
- package/src/styles/components/reagent-editor.css +510 -0
- package/src/styles/components/reagent-list.css +407 -0
- package/src/styles/components/resource-card.css +360 -0
- package/src/styles/components/sample-hierarchy-tree.css +314 -0
- package/src/styles/components/sample-legend.css +201 -0
- package/src/styles/components/sample-selector.css +751 -0
- package/src/styles/components/schedule-calendar.css +478 -0
- package/src/styles/components/scientific-number.css +63 -0
- package/src/styles/components/segmented-control.css +197 -0
- package/src/styles/components/select.css +77 -0
- package/src/styles/components/sequence-input.css +184 -0
- package/src/styles/components/settings-button.css +94 -0
- package/src/styles/components/settings-modal.css +95 -0
- package/src/styles/components/skeleton.css +49 -0
- package/src/styles/components/slider.css +74 -0
- package/src/styles/components/status-indicator.css +66 -0
- package/src/styles/components/step-wizard.css +192 -0
- package/src/styles/components/tabs.css +95 -0
- package/src/styles/components/tags-input.css +195 -0
- package/src/styles/components/textarea.css +82 -0
- package/src/styles/components/theme-toggle.css +69 -0
- package/src/styles/components/time-picker.css +171 -0
- package/src/styles/components/time-range-input.css +42 -0
- package/src/styles/components/toast.css +91 -0
- package/src/styles/components/toggle.css +146 -0
- package/src/styles/components/tooltip.css +91 -0
- package/src/styles/components/unit-input.css +123 -0
- package/src/styles/components/well-edit-popup.css +252 -0
- package/src/styles/components/well-plate.css +307 -0
- package/src/styles/index.css +87 -0
- package/src/styles/variables.css +1117 -0
- package/src/tailwind.preset.ts +61 -0
- package/src/types/auth.ts +55 -0
- package/src/types/auto-group.ts +40 -0
- package/src/types/components.ts +710 -0
- package/src/types/form-builder.ts +197 -0
- package/src/types/index.ts +207 -0
- package/src/types/platform.ts +116 -0
- package/src/utils/color.ts +96 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Paired numeric + unit input for reagent concentrations (pM–M, mg/mL, etc.) with optional molar-mass conversion hint. */
|
|
3
|
+
import { computed, watch } from 'vue'
|
|
4
|
+
import {
|
|
5
|
+
useConcentrationUnits,
|
|
6
|
+
type ConcentrationValue,
|
|
7
|
+
type ConcentrationUnit,
|
|
8
|
+
} from '../composables/useConcentrationUnits'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
modelValue?: ConcentrationValue
|
|
12
|
+
allowedUnits?: ConcentrationUnit[]
|
|
13
|
+
showConversion?: boolean
|
|
14
|
+
molecularWeight?: number
|
|
15
|
+
min?: number
|
|
16
|
+
max?: number
|
|
17
|
+
disabled?: boolean
|
|
18
|
+
error?: boolean
|
|
19
|
+
size?: 'sm' | 'md' | 'lg'
|
|
20
|
+
placeholder?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
+
showConversion: true,
|
|
25
|
+
disabled: false,
|
|
26
|
+
error: false,
|
|
27
|
+
size: 'md',
|
|
28
|
+
placeholder: 'Enter value',
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
'update:modelValue': [value: ConcentrationValue | undefined]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const { unitCategories, getConversionHint } = useConcentrationUnits()
|
|
36
|
+
|
|
37
|
+
// Filter categories based on allowedUnits
|
|
38
|
+
const filteredCategories = computed(() => {
|
|
39
|
+
if (!props.allowedUnits || props.allowedUnits.length === 0) {
|
|
40
|
+
return unitCategories.value
|
|
41
|
+
}
|
|
42
|
+
return unitCategories.value
|
|
43
|
+
.map(cat => ({
|
|
44
|
+
label: cat.label,
|
|
45
|
+
units: cat.units.filter(u => props.allowedUnits!.includes(u)),
|
|
46
|
+
}))
|
|
47
|
+
.filter(cat => cat.units.length > 0)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Flatten all available units
|
|
51
|
+
const availableUnits = computed(() => {
|
|
52
|
+
return filteredCategories.value.flatMap(cat => cat.units)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// Current value and unit
|
|
56
|
+
const currentValue = computed(() => props.modelValue?.value)
|
|
57
|
+
const currentUnit = computed(() => props.modelValue?.unit || availableUnits.value[0] || 'µM')
|
|
58
|
+
|
|
59
|
+
// Conversion hint
|
|
60
|
+
const conversionHint = computed(() => {
|
|
61
|
+
if (!props.showConversion || !props.modelValue) return null
|
|
62
|
+
return getConversionHint(props.modelValue)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
function handleValueInput(event: Event) {
|
|
66
|
+
const target = event.target as HTMLInputElement
|
|
67
|
+
const value = target.value === '' ? undefined : Number(target.value)
|
|
68
|
+
|
|
69
|
+
if (value === undefined || isNaN(value)) {
|
|
70
|
+
emit('update:modelValue', undefined)
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Apply min/max constraints
|
|
75
|
+
let clampedValue = value
|
|
76
|
+
if (props.min !== undefined && clampedValue < props.min) {
|
|
77
|
+
clampedValue = props.min
|
|
78
|
+
}
|
|
79
|
+
if (props.max !== undefined && clampedValue > props.max) {
|
|
80
|
+
clampedValue = props.max
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
emit('update:modelValue', {
|
|
84
|
+
value: clampedValue,
|
|
85
|
+
unit: currentUnit.value,
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function handleUnitChange(event: Event) {
|
|
90
|
+
const target = event.target as HTMLSelectElement
|
|
91
|
+
const unit = target.value as ConcentrationUnit
|
|
92
|
+
|
|
93
|
+
emit('update:modelValue', {
|
|
94
|
+
value: currentValue.value ?? 0,
|
|
95
|
+
unit,
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Ensure modelValue always has a valid unit
|
|
100
|
+
watch(availableUnits, (units) => {
|
|
101
|
+
if (props.modelValue && !units.includes(props.modelValue.unit)) {
|
|
102
|
+
emit('update:modelValue', {
|
|
103
|
+
value: props.modelValue.value,
|
|
104
|
+
unit: units[0] || 'µM',
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}, { immediate: true })
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<template>
|
|
111
|
+
<div
|
|
112
|
+
:class="[
|
|
113
|
+
'mld-concentration-input',
|
|
114
|
+
error ? 'mld-concentration-input--error' : '',
|
|
115
|
+
disabled ? 'mld-concentration-input--disabled' : '',
|
|
116
|
+
]"
|
|
117
|
+
>
|
|
118
|
+
<div :class="['mld-concentration-input__controls', `mld-concentration-input__controls--${size}`]">
|
|
119
|
+
<input
|
|
120
|
+
type="number"
|
|
121
|
+
:value="currentValue"
|
|
122
|
+
:min="min"
|
|
123
|
+
:max="max"
|
|
124
|
+
:disabled="disabled"
|
|
125
|
+
:placeholder="placeholder"
|
|
126
|
+
:class="[
|
|
127
|
+
'mld-concentration-input__value',
|
|
128
|
+
`mld-concentration-input__value--${size}`,
|
|
129
|
+
disabled ? 'mld-concentration-input__value--disabled' : '',
|
|
130
|
+
]"
|
|
131
|
+
aria-label="Concentration value"
|
|
132
|
+
@input="handleValueInput"
|
|
133
|
+
/>
|
|
134
|
+
|
|
135
|
+
<div class="mld-concentration-input__unit">
|
|
136
|
+
<select
|
|
137
|
+
:value="currentUnit"
|
|
138
|
+
:disabled="disabled"
|
|
139
|
+
:class="[
|
|
140
|
+
'mld-concentration-input__unit-select',
|
|
141
|
+
`mld-concentration-input__unit-select--${size}`,
|
|
142
|
+
]"
|
|
143
|
+
aria-label="Concentration unit"
|
|
144
|
+
@change="handleUnitChange"
|
|
145
|
+
>
|
|
146
|
+
<template v-for="category in filteredCategories" :key="category.label">
|
|
147
|
+
<optgroup
|
|
148
|
+
v-if="filteredCategories.length > 1"
|
|
149
|
+
:label="category.label"
|
|
150
|
+
class="mld-concentration-input__unit-group"
|
|
151
|
+
>
|
|
152
|
+
<option
|
|
153
|
+
v-for="unit in category.units"
|
|
154
|
+
:key="unit"
|
|
155
|
+
:value="unit"
|
|
156
|
+
>
|
|
157
|
+
{{ unit }}
|
|
158
|
+
</option>
|
|
159
|
+
</optgroup>
|
|
160
|
+
<template v-else>
|
|
161
|
+
<option
|
|
162
|
+
v-for="unit in category.units"
|
|
163
|
+
:key="unit"
|
|
164
|
+
:value="unit"
|
|
165
|
+
>
|
|
166
|
+
{{ unit }}
|
|
167
|
+
</option>
|
|
168
|
+
</template>
|
|
169
|
+
</template>
|
|
170
|
+
</select>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div
|
|
175
|
+
v-if="showConversion && conversionHint"
|
|
176
|
+
class="mld-concentration-input__conversion"
|
|
177
|
+
>
|
|
178
|
+
{{ conversionHint }}
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</template>
|
|
182
|
+
|
|
183
|
+
<style>
|
|
184
|
+
@import '../styles/components/concentration-input.css';
|
|
185
|
+
</style>
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import ConfirmDialog from './ConfirmDialog.vue'
|
|
4
|
+
import BaseButton from './BaseButton.vue'
|
|
5
|
+
import type { ConfirmVariant } from '../types'
|
|
6
|
+
|
|
7
|
+
const variants: ConfirmVariant[] = ['danger', 'warning', 'info']
|
|
8
|
+
|
|
9
|
+
const dialogOpen = ref(false)
|
|
10
|
+
const dangerOpen = ref(false)
|
|
11
|
+
const warningOpen = ref(false)
|
|
12
|
+
const infoOpen = ref(false)
|
|
13
|
+
const loadingOpen = ref(false)
|
|
14
|
+
const saveOpen = ref(false)
|
|
15
|
+
const uninstallOpen = ref(false)
|
|
16
|
+
const isLoading = ref(false)
|
|
17
|
+
const lastAction = ref<string>('')
|
|
18
|
+
|
|
19
|
+
function log(action: string) {
|
|
20
|
+
lastAction.value = action
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function handleConfirmLoading() {
|
|
24
|
+
isLoading.value = true
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
isLoading.value = false
|
|
27
|
+
loadingOpen.value = false
|
|
28
|
+
log('submitted')
|
|
29
|
+
}, 2000)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function initPlayground() {
|
|
33
|
+
return {
|
|
34
|
+
title: 'Delete experiment',
|
|
35
|
+
subtitle: 'EXP-2024-001 · Dose-response',
|
|
36
|
+
message: 'This will permanently delete the experiment and all associated data. This action cannot be undone.',
|
|
37
|
+
variant: 'danger' as ConfirmVariant,
|
|
38
|
+
confirmLabel: 'Delete',
|
|
39
|
+
cancelLabel: 'Cancel',
|
|
40
|
+
loading: false,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<Story title="Layout/ConfirmDialog">
|
|
47
|
+
<!-- Playground — all props wired, BaseButton trigger -->
|
|
48
|
+
<Variant title="Playground" :init-state="initPlayground">
|
|
49
|
+
<template #default="{ state }">
|
|
50
|
+
<div style="padding: 2rem; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem;">
|
|
51
|
+
<BaseButton variant="secondary" @click="dialogOpen = true">Open dialog</BaseButton>
|
|
52
|
+
<div v-if="lastAction" style="font-family: 'Fira Code', monospace; font-size: 0.75rem; color: var(--text-muted);">
|
|
53
|
+
Last event: <code>{{ lastAction }}</code>
|
|
54
|
+
</div>
|
|
55
|
+
<ConfirmDialog
|
|
56
|
+
v-model="dialogOpen"
|
|
57
|
+
:title="state.title"
|
|
58
|
+
:subtitle="state.subtitle"
|
|
59
|
+
:message="state.message"
|
|
60
|
+
:variant="state.variant"
|
|
61
|
+
:confirm-label="state.confirmLabel"
|
|
62
|
+
:cancel-label="state.cancelLabel"
|
|
63
|
+
:loading="state.loading"
|
|
64
|
+
@confirm="() => { dialogOpen = false; log('confirm') }"
|
|
65
|
+
@cancel="log('cancel')"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<template #controls="{ state }">
|
|
71
|
+
<HstText v-model="state.title" title="Title" />
|
|
72
|
+
<HstText v-model="state.subtitle" title="Subtitle (context line)" />
|
|
73
|
+
<HstText v-model="state.message" title="Message" />
|
|
74
|
+
<HstSelect
|
|
75
|
+
v-model="state.variant"
|
|
76
|
+
title="Variant"
|
|
77
|
+
:options="variants.map(v => ({ label: v, value: v }))"
|
|
78
|
+
/>
|
|
79
|
+
<HstText v-model="state.confirmLabel" title="Confirm label" />
|
|
80
|
+
<HstText v-model="state.cancelLabel" title="Cancel label" />
|
|
81
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
82
|
+
</template>
|
|
83
|
+
</Variant>
|
|
84
|
+
|
|
85
|
+
<!-- Plugin uninstall — the canonical refresh-design pattern with subtitle -->
|
|
86
|
+
<Variant title="Plugin uninstall" :init-state="() => ({})">
|
|
87
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
88
|
+
<BaseButton variant="danger" @click="uninstallOpen = true">Uninstall plugin</BaseButton>
|
|
89
|
+
<ConfirmDialog
|
|
90
|
+
v-model="uninstallOpen"
|
|
91
|
+
title="Confirm uninstall"
|
|
92
|
+
subtitle="mld-plugin-metabolomics · v2.4.1"
|
|
93
|
+
message="Removing this plugin will delete its routes from the platform on next restart. Plugin data and registered experiment types will be preserved."
|
|
94
|
+
variant="danger"
|
|
95
|
+
confirm-label="Uninstall"
|
|
96
|
+
@confirm="() => { uninstallOpen = false; log('uninstalled metabolomics') }"
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
<p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
|
|
100
|
+
The canonical refresh layout: title + subtitle (plugin name · version) sit in the modal header; body holds
|
|
101
|
+
only the explanatory message; red confirm carries the variant intent — no icon needed.
|
|
102
|
+
</p>
|
|
103
|
+
</Variant>
|
|
104
|
+
|
|
105
|
+
<!-- Danger — destructive, the canonical use case -->
|
|
106
|
+
<Variant title="Danger" :init-state="() => ({})">
|
|
107
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
108
|
+
<BaseButton variant="danger" @click="dangerOpen = true">Delete experiment</BaseButton>
|
|
109
|
+
<ConfirmDialog
|
|
110
|
+
v-model="dangerOpen"
|
|
111
|
+
title="Delete Experiment"
|
|
112
|
+
message="Are you sure you want to delete this experiment? All associated data, plates, and analysis results will be permanently removed. This action cannot be undone."
|
|
113
|
+
variant="danger"
|
|
114
|
+
confirm-label="Delete"
|
|
115
|
+
@confirm="() => { dangerOpen = false; log('deleted') }"
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
</Variant>
|
|
119
|
+
|
|
120
|
+
<!-- Warning — discard unsaved changes -->
|
|
121
|
+
<Variant title="Warning" :init-state="() => ({})">
|
|
122
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
123
|
+
<BaseButton variant="secondary" @click="warningOpen = true">Reset analysis</BaseButton>
|
|
124
|
+
<ConfirmDialog
|
|
125
|
+
v-model="warningOpen"
|
|
126
|
+
title="Reset Analysis"
|
|
127
|
+
message="This will discard all unsaved changes and reset the analysis to its initial state. Do you want to continue?"
|
|
128
|
+
variant="warning"
|
|
129
|
+
confirm-label="Reset"
|
|
130
|
+
@confirm="() => { warningOpen = false; log('reset') }"
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
</Variant>
|
|
134
|
+
|
|
135
|
+
<!-- Info — positive affirmation (CTA proceeding with an action) -->
|
|
136
|
+
<Variant title="Info" :init-state="() => ({})">
|
|
137
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
138
|
+
<BaseButton variant="primary" @click="infoOpen = true">Export data</BaseButton>
|
|
139
|
+
<ConfirmDialog
|
|
140
|
+
v-model="infoOpen"
|
|
141
|
+
title="Export Data"
|
|
142
|
+
message="This will generate a CSV export of all 96 wells across 3 plates. The download will start automatically."
|
|
143
|
+
variant="info"
|
|
144
|
+
confirm-label="Export"
|
|
145
|
+
@confirm="() => { infoOpen = false; log('exported') }"
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
</Variant>
|
|
149
|
+
|
|
150
|
+
<!-- Save to Experiment — the actual ExperimentPopover flow -->
|
|
151
|
+
<Variant title="Save to Experiment" :init-state="() => ({})">
|
|
152
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
153
|
+
<BaseButton variant="primary" @click="saveOpen = true">Save to EXP-042</BaseButton>
|
|
154
|
+
<ConfirmDialog
|
|
155
|
+
v-model="saveOpen"
|
|
156
|
+
title="Save to Experiment"
|
|
157
|
+
message="Save current data to DRP Dose-Response Screen · March 2026?"
|
|
158
|
+
variant="info"
|
|
159
|
+
confirm-label="Save"
|
|
160
|
+
@confirm="() => { saveOpen = false; log('saved to EXP-042') }"
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
<p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
|
|
164
|
+
The exact dialog raised from <code>ExperimentPopover</code> when the user clicks the inline save in the topbar
|
|
165
|
+
with <code>confirmSave: true</code>.
|
|
166
|
+
</p>
|
|
167
|
+
</Variant>
|
|
168
|
+
|
|
169
|
+
<!-- Loading state — confirm button shows spinner, dialog stays open -->
|
|
170
|
+
<Variant title="Loading state" :init-state="() => ({})">
|
|
171
|
+
<div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
|
|
172
|
+
<BaseButton variant="primary" @click="loadingOpen = true">Submit results</BaseButton>
|
|
173
|
+
<ConfirmDialog
|
|
174
|
+
v-model="loadingOpen"
|
|
175
|
+
title="Submit Results"
|
|
176
|
+
message="Submit the analysis results to the platform? This may take a moment."
|
|
177
|
+
variant="info"
|
|
178
|
+
confirm-label="Submit"
|
|
179
|
+
:loading="isLoading"
|
|
180
|
+
@confirm="handleConfirmLoading"
|
|
181
|
+
/>
|
|
182
|
+
</div>
|
|
183
|
+
<p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
|
|
184
|
+
Click Submit → confirm button spins for 2s, cancel disables, overlay click/escape blocked while loading.
|
|
185
|
+
</p>
|
|
186
|
+
</Variant>
|
|
187
|
+
</Story>
|
|
188
|
+
</template>
|
|
189
|
+
|
|
190
|
+
<docs lang="md">
|
|
191
|
+
## ConfirmDialog
|
|
192
|
+
|
|
193
|
+
A compact modal for confirming a decision. Wraps `BaseModal` (inheriting its
|
|
194
|
+
refresh-design container polish: 2-layer shadow, lighter overlay, 15px title
|
|
195
|
+
hierarchy, horizontal divider between header and body).
|
|
196
|
+
|
|
197
|
+
### Anatomy (refresh layout)
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
┌─────────────────────────────────────────────┐
|
|
201
|
+
│ Title × │ ← BaseModal header
|
|
202
|
+
│ Subtitle line (context) │ (title + optional subtitle)
|
|
203
|
+
├─────────────────────────────────────────────┤
|
|
204
|
+
│ │
|
|
205
|
+
│ The message explains what will happen and │ ← body: just the message
|
|
206
|
+
│ any consequences the user should know. │
|
|
207
|
+
│ │
|
|
208
|
+
├─────────────────────────────────────────────┤
|
|
209
|
+
│ [ Cancel ] [ Action ] │ ← footer: buttons flush-right
|
|
210
|
+
└─────────────────────────────────────────────┘
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
- **Title + subtitle** live at the top in `BaseModal`'s header — the subtitle is
|
|
214
|
+
a one-line context string (plugin name · version, experiment code, etc.)
|
|
215
|
+
- **Body** holds only the message. No forced icon sidebar — the variant's intent
|
|
216
|
+
is carried by the confirm button's color
|
|
217
|
+
- **Icon is opt-in**: pass a `#icon` slot only if your message needs an extra
|
|
218
|
+
visual signal. Most confirmations don't.
|
|
219
|
+
|
|
220
|
+
### Button tactile system
|
|
221
|
+
|
|
222
|
+
The Cancel + Confirm buttons use the **same system as BaseButton**:
|
|
223
|
+
|
|
224
|
+
- Hover: `translateY(-1px)` + `var(--shadow-sm)` over 150ms with `--mint-ease-out-quart`
|
|
225
|
+
- Press: snap to `translateY(0)`, shadow cleared, gradient flattened at 50ms
|
|
226
|
+
- Filled confirm gets the 12% white gradient overlay
|
|
227
|
+
- `prefers-reduced-motion` guarded
|
|
228
|
+
|
|
229
|
+
### Variant semantics
|
|
230
|
+
|
|
231
|
+
| Variant | Confirm button color | When to use |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| `danger` | `--mint-error` | Destructive or irreversible actions (delete, uninstall, drop table) |
|
|
234
|
+
| `warning` | `--mint-warning` | Potentially lossy actions (discard unsaved, overwrite config) |
|
|
235
|
+
| `info` | `--color-primary` | Affirmative CTAs (save, submit, export, publish) |
|
|
236
|
+
|
|
237
|
+
**Why `info` uses `--color-primary` not `--mint-info`**: info-as-CTA means
|
|
238
|
+
"proceed with this positive action" — it should match the primary button color,
|
|
239
|
+
not the informational-banner cyan that's reserved for non-action status pills.
|
|
240
|
+
|
|
241
|
+
### Loading state contract
|
|
242
|
+
|
|
243
|
+
When `loading: true`:
|
|
244
|
+
- Confirm button replaces its label with a spinner, disables hover
|
|
245
|
+
- Cancel button is disabled
|
|
246
|
+
- Overlay click and Escape-to-close are both blocked — the user can't
|
|
247
|
+
accidentally dismiss an in-flight operation
|
|
248
|
+
</docs>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Confirm/cancel dialog with danger, warning, and info variants; blocks close while loading. */
|
|
3
|
+
import BaseModal from './BaseModal.vue'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
modelValue: boolean
|
|
7
|
+
title?: string
|
|
8
|
+
subtitle?: string
|
|
9
|
+
message?: string
|
|
10
|
+
variant?: 'danger' | 'warning' | 'info'
|
|
11
|
+
confirmLabel?: string
|
|
12
|
+
cancelLabel?: string
|
|
13
|
+
loading?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
withDefaults(defineProps<Props>(), {
|
|
17
|
+
title: 'Confirm',
|
|
18
|
+
variant: 'danger',
|
|
19
|
+
confirmLabel: 'Confirm',
|
|
20
|
+
cancelLabel: 'Cancel',
|
|
21
|
+
loading: false,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const emit = defineEmits<{
|
|
25
|
+
'update:modelValue': [value: boolean]
|
|
26
|
+
confirm: []
|
|
27
|
+
cancel: []
|
|
28
|
+
}>()
|
|
29
|
+
|
|
30
|
+
function handleCancel() {
|
|
31
|
+
emit('update:modelValue', false)
|
|
32
|
+
emit('cancel')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleConfirm() {
|
|
36
|
+
emit('confirm')
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<BaseModal
|
|
42
|
+
:model-value="modelValue"
|
|
43
|
+
:title="title"
|
|
44
|
+
:subtitle="subtitle"
|
|
45
|
+
size="sm"
|
|
46
|
+
:closable="!loading"
|
|
47
|
+
:close-on-overlay="!loading"
|
|
48
|
+
:close-on-escape="!loading"
|
|
49
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
50
|
+
>
|
|
51
|
+
<div class="mld-confirm">
|
|
52
|
+
<!-- Icon is now opt-in via slot. Refresh design keeps the body focused on
|
|
53
|
+
the message; variant intent is carried by the confirm button's color. -->
|
|
54
|
+
<div
|
|
55
|
+
v-if="$slots.icon"
|
|
56
|
+
:class="['mld-confirm__icon', `mld-confirm__icon--${variant}`]"
|
|
57
|
+
>
|
|
58
|
+
<slot name="icon" />
|
|
59
|
+
</div>
|
|
60
|
+
<p v-if="message" class="mld-confirm__message">{{ message }}</p>
|
|
61
|
+
<slot />
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<template #footer>
|
|
65
|
+
<div class="mld-confirm__footer">
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
class="mld-confirm__btn-cancel"
|
|
69
|
+
:disabled="loading"
|
|
70
|
+
@click="handleCancel"
|
|
71
|
+
>
|
|
72
|
+
{{ cancelLabel }}
|
|
73
|
+
</button>
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
:class="['mld-confirm__btn-confirm', `mld-confirm__btn-confirm--${variant}`]"
|
|
77
|
+
:disabled="loading"
|
|
78
|
+
@click="handleConfirm"
|
|
79
|
+
>
|
|
80
|
+
<svg v-if="loading" class="mld-confirm__btn-spinner" fill="none" viewBox="0 0 24 24">
|
|
81
|
+
<circle style="opacity: 0.25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
|
|
82
|
+
<path style="opacity: 0.75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
|
|
83
|
+
</svg>
|
|
84
|
+
{{ confirmLabel }}
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
88
|
+
</BaseModal>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
@import '../styles/components/confirm-dialog.css';
|
|
93
|
+
</style>
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import DataFrame from './DataFrame.vue'
|
|
4
|
+
import type { DataFrameColumn, PaginationState } from '../types'
|
|
5
|
+
|
|
6
|
+
const columns: DataFrameColumn[] = [
|
|
7
|
+
{ key: 'id', label: 'ID', sortable: true, width: 60, align: 'center' },
|
|
8
|
+
{ key: 'compound', label: 'Compound', sortable: true },
|
|
9
|
+
{ key: 'concentration', label: 'Conc. (uM)', sortable: true, align: 'right' },
|
|
10
|
+
{ key: 'response', label: 'Response (%)', sortable: true, align: 'right' },
|
|
11
|
+
{ key: 'well', label: 'Well', align: 'center' },
|
|
12
|
+
{ key: 'status', label: 'Status' },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
const data = [
|
|
16
|
+
{ id: 1, compound: 'MINT-2847', concentration: 10.0, response: 95.2, well: 'A1', status: 'Pass' },
|
|
17
|
+
{ id: 2, compound: 'MINT-2847', concentration: 3.33, response: 82.1, well: 'A2', status: 'Pass' },
|
|
18
|
+
{ id: 3, compound: 'MINT-2847', concentration: 1.11, response: 54.7, well: 'A3', status: 'Pass' },
|
|
19
|
+
{ id: 4, compound: 'MINT-2847', concentration: 0.37, response: 23.4, well: 'A4', status: 'Pass' },
|
|
20
|
+
{ id: 5, compound: 'MINT-2847', concentration: 0.12, response: 8.9, well: 'A5', status: 'Pass' },
|
|
21
|
+
{ id: 6, compound: 'MINT-3192', concentration: 10.0, response: 88.7, well: 'B1', status: 'Pass' },
|
|
22
|
+
{ id: 7, compound: 'MINT-3192', concentration: 3.33, response: 71.3, well: 'B2', status: 'Pass' },
|
|
23
|
+
{ id: 8, compound: 'MINT-3192', concentration: 1.11, response: 45.2, well: 'B3', status: 'Flagged' },
|
|
24
|
+
{ id: 9, compound: 'MINT-3192', concentration: 0.37, response: 18.6, well: 'B4', status: 'Pass' },
|
|
25
|
+
{ id: 10, compound: 'MINT-3192', concentration: 0.12, response: 5.1, well: 'B5', status: 'Pass' },
|
|
26
|
+
{ id: 11, compound: 'Vehicle', concentration: 0, response: 2.3, well: 'C1', status: 'Pass' },
|
|
27
|
+
{ id: 12, compound: 'Vehicle', concentration: 0, response: 1.8, well: 'C2', status: 'Pass' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const selectedKeys = ref<(string | number)[]>([])
|
|
31
|
+
const pagination = ref<PaginationState>({ page: 1, pageSize: 5, total: data.length })
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<Story title="Data Display/DataFrame">
|
|
36
|
+
<Variant title="Playground">
|
|
37
|
+
<template #default="{ state }">
|
|
38
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
39
|
+
<DataFrame
|
|
40
|
+
:data="data"
|
|
41
|
+
:columns="columns"
|
|
42
|
+
row-key="id"
|
|
43
|
+
:striped="state.striped"
|
|
44
|
+
:bordered="state.bordered"
|
|
45
|
+
:sortable="state.sortable"
|
|
46
|
+
:searchable="state.searchable"
|
|
47
|
+
:selectable="state.selectable"
|
|
48
|
+
:loading="state.loading"
|
|
49
|
+
:size="state.size"
|
|
50
|
+
:sticky-header="state.stickyHeader"
|
|
51
|
+
:selected-keys="selectedKeys"
|
|
52
|
+
@update:selected-keys="selectedKeys = $event"
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<template #controls="{ state }">
|
|
58
|
+
<HstSelect
|
|
59
|
+
v-model="state.size"
|
|
60
|
+
title="Size"
|
|
61
|
+
:options="['sm', 'md', 'lg'].map(s => ({ label: s, value: s }))"
|
|
62
|
+
/>
|
|
63
|
+
<HstCheckbox v-model="state.striped" title="Striped" />
|
|
64
|
+
<HstCheckbox v-model="state.bordered" title="Bordered" />
|
|
65
|
+
<HstCheckbox v-model="state.sortable" title="Sortable" />
|
|
66
|
+
<HstCheckbox v-model="state.searchable" title="Searchable" />
|
|
67
|
+
<HstCheckbox v-model="state.selectable" title="Selectable" />
|
|
68
|
+
<HstCheckbox v-model="state.stickyHeader" title="Sticky Header" />
|
|
69
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
70
|
+
</template>
|
|
71
|
+
</Variant>
|
|
72
|
+
|
|
73
|
+
<Variant title="Sortable with Search">
|
|
74
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
75
|
+
<DataFrame
|
|
76
|
+
:data="data"
|
|
77
|
+
:columns="columns"
|
|
78
|
+
row-key="id"
|
|
79
|
+
sortable
|
|
80
|
+
searchable
|
|
81
|
+
search-placeholder="Search compounds, wells..."
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
</Variant>
|
|
85
|
+
|
|
86
|
+
<Variant title="With Pagination">
|
|
87
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
88
|
+
<DataFrame
|
|
89
|
+
:data="data"
|
|
90
|
+
:columns="columns"
|
|
91
|
+
row-key="id"
|
|
92
|
+
sortable
|
|
93
|
+
:pagination="pagination"
|
|
94
|
+
@update:pagination="pagination = $event"
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
</Variant>
|
|
98
|
+
|
|
99
|
+
<Variant title="Selectable Rows">
|
|
100
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
101
|
+
<DataFrame
|
|
102
|
+
:data="data"
|
|
103
|
+
:columns="columns"
|
|
104
|
+
row-key="id"
|
|
105
|
+
selectable
|
|
106
|
+
:selected-keys="selectedKeys"
|
|
107
|
+
@update:selected-keys="selectedKeys = $event"
|
|
108
|
+
/>
|
|
109
|
+
<p style="margin-top: 1rem; font-size: 0.875rem; color: var(--text-muted, #94a3b8);">
|
|
110
|
+
Selected IDs: {{ selectedKeys.length ? selectedKeys.join(', ') : 'none' }}
|
|
111
|
+
</p>
|
|
112
|
+
</div>
|
|
113
|
+
</Variant>
|
|
114
|
+
|
|
115
|
+
<Variant title="Loading State">
|
|
116
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
117
|
+
<DataFrame
|
|
118
|
+
:data="[]"
|
|
119
|
+
:columns="columns"
|
|
120
|
+
loading
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
</Variant>
|
|
124
|
+
|
|
125
|
+
<Variant title="Empty State">
|
|
126
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
127
|
+
<DataFrame
|
|
128
|
+
:data="[]"
|
|
129
|
+
:columns="columns"
|
|
130
|
+
empty-text="No experiment results found. Run an analysis to populate this table."
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
</Variant>
|
|
134
|
+
|
|
135
|
+
<Variant title="Compact (sm)">
|
|
136
|
+
<div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
|
|
137
|
+
<DataFrame
|
|
138
|
+
:data="data"
|
|
139
|
+
:columns="columns"
|
|
140
|
+
row-key="id"
|
|
141
|
+
size="sm"
|
|
142
|
+
sortable
|
|
143
|
+
bordered
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</Variant>
|
|
147
|
+
</Story>
|
|
148
|
+
</template>
|