@morscherlab/mint-sdk 1.4.0-beta.2 → 1.4.0-beta.21
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 +14 -3
- package/dist/{ActionMenu-CScINahU.js → AlertBox-DwgNTEqf.js} +40 -209
- package/dist/AlertBox-DwgNTEqf.js.map +1 -0
- package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-CZZaxni0.js} +1249 -239
- package/dist/AppSidebar-CZZaxni0.js.map +1 -0
- package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CjWoxAD1.js} +2 -2
- package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CjWoxAD1.js.map} +1 -1
- package/dist/ExperimentPopover-DujiuQIO.js +337 -0
- package/dist/ExperimentPopover-DujiuQIO.js.map +1 -0
- package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-B4j4eUOJ.js} +244 -211
- package/dist/ExperimentSelectorModal-B4j4eUOJ.js.map +1 -0
- package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-DyUPH3I5.js} +2 -2
- package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-DyUPH3I5.js.map} +1 -1
- package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-D2MOOtuO.js} +28 -27
- package/dist/SettingsModal-D2MOOtuO.js.map +1 -0
- package/dist/__stories__/experiment-helpers.d.ts +10 -0
- package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
- package/dist/__tests__/components/FloatingPanelsInModal.test.d.ts +1 -0
- package/dist/__tests__/composables/useFloatingPanel.test.d.ts +1 -0
- package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
- package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
- package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/AppTopBar.vue.d.ts +20 -5
- package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
- package/dist/components/AuditTrail.vue.d.ts +1 -1
- package/dist/components/BaseButton.vue.d.ts +4 -2
- package/dist/components/BaseSelect.vue.d.ts +2 -2
- package/dist/components/ChartContainer.vue.d.ts +2 -0
- package/dist/components/DatePicker.vue.d.ts +1 -1
- package/dist/components/ExperimentPopover.vue.d.ts +18 -0
- package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -5
- package/dist/components/FilePicker.vue.d.ts +1 -1
- package/dist/components/FileUploader.vue.d.ts +2 -2
- package/dist/components/JobsStatusTray.vue.d.ts +15 -4
- package/dist/components/PluginIcon.vue.d.ts +2 -2
- package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
- package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
- package/dist/components/SampleSelector.vue.d.ts +6 -6
- package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -3
- package/dist/components/StepWizard.vue.d.ts +3 -0
- package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
- package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
- package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +3 -3
- package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
- package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
- package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
- package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
- package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
- package/dist/composables/createClient.d.ts +2 -0
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/pluginIdentity.d.ts +24 -0
- package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
- package/dist/composables/useAppExperiment.d.ts +8 -0
- package/dist/composables/useCalendarGrid.d.ts +1 -1
- package/dist/composables/useExperimentSelector.d.ts +6 -2
- package/dist/composables/useFileImport.d.ts +7 -0
- package/dist/composables/useFloatingPanel.d.ts +29 -0
- package/dist/composables/useJobCenter.d.ts +41 -3
- package/dist/composables/useOnboarding.d.ts +119 -0
- package/dist/composables/usePlatform.d.ts +1 -0
- package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-Bsg0t5Ab.js} +2 -2
- package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-Bsg0t5Ab.js.map} +1 -1
- package/dist/{data-C2PwI_dn.js → data-Boeh4uPI.js} +180 -125
- package/dist/data-Boeh4uPI.js.map +1 -0
- package/dist/data.d.ts +1 -1
- package/dist/data.js +9 -9
- package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
- package/dist/experiment-DyO54FQB.js.map +1 -0
- package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-DCn2QKG7.js} +3 -3
- package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-DCn2QKG7.js.map} +1 -1
- package/dist/index.js +20 -20
- package/dist/{install-DAID6c2-.js → install-BEHp7Mo-.js} +15 -14
- package/dist/{install-DAID6c2-.js.map → install-BEHp7Mo-.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-DLwRl_Ql.js → lab-D61eaX6f.js} +136 -148
- package/dist/lab-D61eaX6f.js.map +1 -0
- package/dist/lab.js +4 -3
- package/dist/{records-BzTcxekG.js → records-D4aQXyZu.js} +647 -389
- package/dist/records-D4aQXyZu.js.map +1 -0
- package/dist/{runtime-D6gVat6r.js → runtime-q-R0CNLh.js} +417 -54
- package/dist/runtime-q-R0CNLh.js.map +1 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +7 -7
- package/dist/{shell-5ju97nOS.js → shell-6CGFvUUw.js} +10 -5
- package/dist/{shell-5ju97nOS.js.map → shell-6CGFvUUw.js.map} +1 -1
- package/dist/shell.d.ts +1 -0
- package/dist/shell.js +6 -6
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js +2 -2
- package/dist/stores/settings.d.ts +4 -12
- package/dist/styles.css +2753 -2101
- package/dist/types/componentWorkflowTypes.d.ts +2 -0
- package/dist/types/components.d.ts +2 -0
- package/dist/types/generated/platformContext.d.ts +1 -0
- package/dist/types/generated-ui.d.ts +4 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/jobs.d.ts +9 -0
- package/dist/types/platform.d.ts +1 -1
- package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-uFIz6Yv8.js} +75 -5
- package/dist/useDropdownState-uFIz6Yv8.js.map +1 -0
- package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-QEFoq4tf.js} +48 -6
- package/dist/useExperimentSamples-QEFoq4tf.js.map +1 -0
- package/dist/{useListReorder-CcbEYxX-.js → useListReorder-DsuzwWGS.js} +219 -437
- package/dist/useListReorder-DsuzwWGS.js.map +1 -0
- package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-KpZ4iJ6o.js} +85 -81
- package/dist/useRackEditor-KpZ4iJ6o.js.map +1 -0
- package/dist/useRealtime-B58Lo-Tm.js +508 -0
- package/dist/useRealtime-B58Lo-Tm.js.map +1 -0
- package/dist/useRequest-BuDmW8Jc.js +215 -0
- package/dist/useRequest-BuDmW8Jc.js.map +1 -0
- package/dist/utils/time.d.ts +7 -0
- package/package.json +3 -2
- package/src/__stories__/experiment-helpers.ts +3 -3
- package/src/__tests__/components/ActionMenu.test.ts +2 -2
- package/src/__tests__/components/AppTopBar.test.ts +257 -3
- package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
- package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
- package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
- package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
- package/src/__tests__/components/BaseButton.test.ts +19 -0
- package/src/__tests__/components/BaseModal.test.ts +13 -0
- package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
- package/src/__tests__/components/BaseSelect.test.ts +2 -1
- package/src/__tests__/components/BatchProgressList.test.ts +16 -0
- package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
- package/src/__tests__/components/ChartContainer.test.ts +11 -0
- package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
- package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
- package/src/__tests__/components/DatePicker.test.ts +21 -0
- package/src/__tests__/components/DatePicker.time.test.ts +2 -2
- package/src/__tests__/components/EmptyState.test.ts +1 -1
- package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
- package/src/__tests__/components/ExperimentSelectorModal.test.ts +153 -14
- package/src/__tests__/components/FloatingPanelsInModal.test.ts +94 -0
- package/src/__tests__/components/GeneratedPluginView.test.ts +23 -2
- package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
- package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
- package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
- package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
- package/src/__tests__/components/SampleSelector.test.ts +33 -8
- package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
- package/src/__tests__/components/SettingsModal.test.ts +9 -2
- package/src/__tests__/components/StepWizard.test.ts +11 -0
- package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
- package/src/__tests__/components/deprecationTags.test.ts +1 -1
- package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
- package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
- package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
- package/src/__tests__/composables/useFileImport.test.ts +36 -0
- package/src/__tests__/composables/useFloatingPanel.test.ts +68 -0
- package/src/__tests__/composables/useJobCenter.test.ts +262 -3
- package/src/__tests__/composables/useOnboarding.test.ts +317 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
- package/src/__tests__/fixtures/table-import/cells.xlsx +0 -0
- package/src/__tests__/fixtures/table-import/samples.xlsx +0 -0
- package/src/__tests__/stores/settings.test.ts +21 -21
- package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
- package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
- package/src/__tests__/styles/cssTokens.test.ts +6 -3
- package/src/__tests__/styles/menusShellRefresh.test.ts +22 -12
- package/src/__tests__/styles/paletteTokens.test.ts +44 -0
- package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
- package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
- package/src/__tests__/utils/time.test.ts +18 -1
- package/src/components/ActionMenu.vue +6 -37
- package/src/components/AdductText.story.vue +7 -0
- package/src/components/AdductText.vue +1 -1
- package/src/components/AlertBox.story.vue +2 -2
- package/src/components/AlertBox.vue +18 -16
- package/src/components/AppSidebar.story.vue +0 -28
- package/src/components/AppTopBar.onboarding.story.vue +69 -0
- package/src/components/AppTopBar.story.vue +105 -15
- package/src/components/AppTopBar.vue +248 -122
- package/src/components/ArtifactSaveDialog.story.vue +23 -0
- package/src/components/ArtifactSaveDialog.vue +102 -12
- package/src/components/AuditTrail.story.vue +2 -1
- package/src/components/AuditTrail.vue +2 -21
- package/src/components/Avatar.vue +10 -14
- package/src/components/BaseButton.vue +16 -2
- package/src/components/BaseModal.vue +2 -1
- package/src/components/BaseSelect.multiple.story.vue +13 -2
- package/src/components/BaseSelect.vue +4 -3
- package/src/components/BatchProgressList.vue +35 -25
- package/src/components/ChartContainer.story.vue +2 -1
- package/src/components/ChartContainer.vue +8 -6
- package/src/components/ConfirmDialog.story.vue +1 -1
- package/src/components/EmptyState.vue +1 -1
- package/src/components/ExperimentPopover.story.vue +165 -53
- package/src/components/ExperimentPopover.vue +169 -187
- package/src/components/ExperimentSelectorModal.story.vue +73 -31
- package/src/components/ExperimentSelectorModal.vue +144 -111
- package/src/components/FormField.story.vue +8 -48
- package/src/components/GeneratedPluginView.vue +11 -10
- package/src/components/GeneratedResultRenderer.vue +3 -4
- package/src/components/InstrumentStateBadge.vue +1 -1
- package/src/components/JobsStatusTray.story.vue +97 -43
- package/src/components/JobsStatusTray.vue +287 -290
- package/src/components/LayoutResizeHandle.story.vue +65 -4
- package/src/components/LoadingSpinner.vue +1 -1
- package/src/components/NumberInput.vue +3 -6
- package/src/components/PluginIcon.story.vue +2 -10
- package/src/components/PluginIcon.vue +2 -2
- package/src/components/PluginWorkspaceView.props.ts +3 -0
- package/src/components/PluginWorkspaceView.story.vue +1 -1
- package/src/components/PluginWorkspaceView.vue +17 -0
- package/src/components/RuntimeUpdateNotice.vue +1 -1
- package/src/components/SampleSelector.story.vue +22 -7
- package/src/components/SampleSelector.vue +34 -37
- package/src/components/SampleSelectorGroupNode.vue +1 -1
- package/src/components/SectionCard.story.vue +35 -2
- package/src/components/SequenceProgressBar.story.vue +9 -0
- package/src/components/SequenceProgressBar.vue +6 -1
- package/src/components/SettingsModal.schema.ts +1 -1
- package/src/components/SettingsModal.vue +9 -14
- package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
- package/src/components/SmartGroupManual.story.vue +1 -1
- package/src/components/StepWizard.story.vue +33 -0
- package/src/components/StepWizard.vue +8 -1
- package/src/components/Tooltip.vue +9 -32
- package/src/components/WellPlate.story.vue +3 -1
- package/src/components/WellPlate.vue +7 -0
- package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
- package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
- package/src/components/internal/DatePickerDateInternal.vue +23 -85
- package/src/components/internal/DatePickerDateTimeInternal.vue +10 -14
- package/src/components/internal/DatePickerTimeInternal.vue +13 -9
- package/src/components/internal/NumberUnitInputInternal.vue +4 -18
- package/src/components/internal/OnboardingLayerInternal.vue +173 -0
- package/src/components/internal/ResourcePickerListInternal.vue +45 -85
- package/src/components/internal/SelectMultipleInternal.vue +187 -65
- package/src/components/internal/SelectSearchableInternal.vue +8 -4
- package/src/components/internal/WellEditPopupInternal.vue +11 -22
- package/src/components/internal/WorkspaceShellInternal.vue +12 -0
- package/src/composables/createClient.ts +2 -0
- package/src/composables/index.ts +1 -0
- package/src/composables/pluginIdentity.ts +31 -0
- package/src/composables/pluginWorkspaceModel.ts +2 -2
- package/src/composables/useAppExperiment.ts +20 -0
- package/src/composables/useCalendarGrid.ts +4 -3
- package/src/composables/useExperimentSelector.ts +77 -31
- package/src/composables/useFileImport.ts +51 -1
- package/src/composables/useFloatingPanel.ts +107 -0
- package/src/composables/useJobCenter.ts +188 -6
- package/src/composables/useOnboarding.ts +465 -0
- package/src/composables/usePluginWorkspace.ts +1 -1
- package/src/data.ts +1 -0
- package/src/runtime.ts +2 -1
- package/src/shell.ts +17 -0
- package/src/stores/index.ts +0 -2
- package/src/stores/settings.ts +20 -50
- package/src/styles/components/action-menu.css +1 -1
- package/src/styles/components/adduct-text.css +13 -5
- package/src/styles/components/alert-box.css +39 -58
- package/src/styles/components/app-layout.css +10 -6
- package/src/styles/components/app-page-selector.css +121 -44
- package/src/styles/components/app-pill-nav.css +11 -12
- package/src/styles/components/app-sidebar.css +9 -18
- package/src/styles/components/app-top-bar.css +219 -55
- package/src/styles/components/artifact-save-dialog.css +153 -2
- package/src/styles/components/audit-trail.css +16 -19
- package/src/styles/components/avatar.css +6 -4
- package/src/styles/components/batch-progress-list.css +38 -36
- package/src/styles/components/button.css +36 -59
- package/src/styles/components/calendar.css +12 -12
- package/src/styles/components/chart-container.css +34 -23
- package/src/styles/components/checkbox.css +2 -12
- package/src/styles/components/collapsible-card.css +27 -29
- package/src/styles/components/confirm-dialog.css +13 -14
- package/src/styles/components/dataframe.css +13 -5
- package/src/styles/components/date-picker.css +84 -94
- package/src/styles/components/datetime-picker.css +35 -47
- package/src/styles/components/divider.css +20 -20
- package/src/styles/components/dose-calculator.css +3 -3
- package/src/styles/components/empty-state.css +20 -17
- package/src/styles/components/experiment-code-badge.css +2 -0
- package/src/styles/components/experiment-popover.css +174 -329
- package/src/styles/components/experiment-selector-modal.css +88 -56
- package/src/styles/components/file-picker.css +3 -3
- package/src/styles/components/file-uploader.css +38 -49
- package/src/styles/components/form-builder.css +3 -3
- package/src/styles/components/formula-input.css +1 -1
- package/src/styles/components/icon-button.css +18 -24
- package/src/styles/components/input.css +5 -4
- package/src/styles/components/instrument-monitor.css +13 -15
- package/src/styles/components/jobs-status-tray.css +140 -296
- package/src/styles/components/layout-resize-handle.css +59 -16
- package/src/styles/components/modal.css +5 -7
- package/src/styles/components/molecule-input.css +2 -2
- package/src/styles/components/multi-select.css +65 -117
- package/src/styles/components/number-input.css +26 -19
- package/src/styles/components/onboarding.css +368 -0
- package/src/styles/components/pill.css +3 -2
- package/src/styles/components/plate-editor.css +0 -1
- package/src/styles/components/plugin-icon.css +26 -23
- package/src/styles/components/popover.css +2 -2
- package/src/styles/components/presence-avatars.css +1 -1
- package/src/styles/components/progress-bar.css +3 -3
- package/src/styles/components/protocol-step-editor.css +1 -3
- package/src/styles/components/resource-card.css +2 -2
- package/src/styles/components/resource-picker-list.css +6 -57
- package/src/styles/components/sample-hierarchy-tree.css +4 -4
- package/src/styles/components/sample-selector.css +138 -79
- package/src/styles/components/schedule-calendar.css +8 -8
- package/src/styles/components/searchable-select.css +15 -19
- package/src/styles/components/section-card.css +54 -49
- package/src/styles/components/segmented-control.css +18 -15
- package/src/styles/components/select.css +3 -3
- package/src/styles/components/sequence-input.css +2 -2
- package/src/styles/components/sequence-progress-bar.css +17 -8
- package/src/styles/components/settings-modal.css +7 -2
- package/src/styles/components/smart-group.css +18 -18
- package/src/styles/components/step-wizard.css +52 -16
- package/src/styles/components/tabs.css +2 -2
- package/src/styles/components/textarea.css +3 -3
- package/src/styles/components/time-picker.css +37 -25
- package/src/styles/components/toast.css +13 -11
- package/src/styles/components/toggle.css +1 -11
- package/src/styles/components/tooltip.css +12 -11
- package/src/styles/components/unit-input.css +9 -8
- package/src/styles/components/well-edit-popup.css +2 -2
- package/src/styles/components/well-plate.css +9 -2
- package/src/styles/index.css +1 -0
- package/src/styles/variables.css +247 -78
- package/src/types/componentWorkflowTypes.ts +2 -0
- package/src/types/components.ts +2 -0
- package/src/types/generated/platformContext.ts +1 -0
- package/src/types/generated-ui.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/jobs.ts +10 -0
- package/src/types/platform.ts +1 -1
- package/src/utils/time.ts +21 -0
- package/dist/ActionMenu-CScINahU.js.map +0 -1
- package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
- package/dist/BaseModal-DfRIuVoj.js.map +0 -1
- package/dist/ExperimentPopover-C4sGw-is.js +0 -359
- package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
- package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
- package/dist/SettingsModal-CSLE31yg.js.map +0 -1
- package/dist/data-C2PwI_dn.js.map +0 -1
- package/dist/experiment-43OJtH7R.js.map +0 -1
- package/dist/lab-DLwRl_Ql.js.map +0 -1
- package/dist/records-BzTcxekG.js.map +0 -1
- package/dist/runtime-D6gVat6r.js.map +0 -1
- package/dist/useExperimentSamples-CxcnxZ8h.js.map +0 -1
- package/dist/useListReorder-CcbEYxX-.js.map +0 -1
- package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
- package/dist/useRealtime-PalKue84.js +0 -696
- package/dist/useRealtime-PalKue84.js.map +0 -1
- package/dist/useRequest-D5JDfsgZ.js +0 -76
- package/dist/useRequest-D5JDfsgZ.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"records-BzTcxekG.js","names":["$attrs","$slots","$slots","$slots","$slots","$slots"],"sources":["../src/components/BaseInput.vue","../src/components/BaseInput.vue","../src/utils/options.ts","../src/composables/useSelectionLimit.ts","../src/composables/useListSelection.ts","../src/components/internal/SelectMultipleInternal.vue","../src/components/internal/SelectMultipleInternal.vue","../src/components/internal/SelectSearchableInternal.vue","../src/components/internal/SelectSearchableInternal.vue","../src/components/BaseSelect.vue","../src/components/BaseSelect.vue","../src/components/Tooltip.vue","../src/components/Tooltip.vue","../src/components/internal/CheckboxSwitchInternal.vue","../src/components/internal/CheckboxSwitchInternal.vue","../src/components/BaseCheckbox.vue","../src/components/BaseCheckbox.vue","../src/composables/useRovingFocus.ts","../src/components/EmptyState.vue","../src/components/EmptyState.vue","../src/components/FormField.vue","../src/components/FormField.vue","../src/composables/useDropdownState.ts","../src/composables/useMenuKeyboard.ts","../src/components/FileUploader.vue","../src/components/FileUploader.vue","../src/composables/experiment-utils.ts","../src/composables/useAppExperiment.ts","../src/utils/pluginSecrets.ts","../src/components/SecretInput.vue","../src/components/SecretInput.vue","../src/components/TagsInput.vue","../src/components/TagsInput.vue","../src/jobs.ts","../src/composables/platformContextHelpers.ts","../src/components/Skeleton.vue","../src/components/Skeleton.vue","../src/components/internal/ResourcePickerListInternal.vue","../src/components/internal/ResourcePickerListInternal.vue","../src/utils/records.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a styled text `<input>`, or a `<textarea>` with `type=\"textarea\"`; size, invalid, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border (input only).\n * Numbers use NumberInput.\n *\n * @example\n * ```vue\n * <BaseInput v-model=\"name\" :invalid=\"!!nameError\" />\n * <BaseInput v-model=\"notes\" type=\"textarea\" :rows=\"4\" />\n * ```\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n maxlength?: number\n list?: string\n ariaDescribedby?: string\n /** Visible text lines (`textarea`). */\n rows?: number\n /** Resize handle (`textarea`). */\n resize?: 'none' | 'vertical' | 'horizontal' | 'both'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n rows: 3,\n resize: 'vertical',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => props.type !== 'textarea' && Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement | HTMLTextAreaElement).value)\n}\n</script>\n\n<template>\n <textarea\n v-if=\"type === 'textarea'\"\n v-bind=\"inputAttrs\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autofocus=\"autofocus\"\n :rows=\"rows\"\n :maxlength=\"maxlength\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-textarea',\n `mint-textarea--${size}`,\n `mint-textarea--resize-${resize}`,\n invalid ? 'mint-textarea--error' : '',\n disabled ? 'mint-textarea--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <div\n v-else-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n invalid ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n invalid ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled text `<input>`, or a `<textarea>` with `type=\"textarea\"`; size, invalid, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border (input only).\n * Numbers use NumberInput.\n *\n * @example\n * ```vue\n * <BaseInput v-model=\"name\" :invalid=\"!!nameError\" />\n * <BaseInput v-model=\"notes\" type=\"textarea\" :rows=\"4\" />\n * ```\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n maxlength?: number\n list?: string\n ariaDescribedby?: string\n /** Visible text lines (`textarea`). */\n rows?: number\n /** Resize handle (`textarea`). */\n resize?: 'none' | 'vertical' | 'horizontal' | 'both'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n rows: 3,\n resize: 'vertical',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => props.type !== 'textarea' && Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement | HTMLTextAreaElement).value)\n}\n</script>\n\n<template>\n <textarea\n v-if=\"type === 'textarea'\"\n v-bind=\"inputAttrs\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autofocus=\"autofocus\"\n :rows=\"rows\"\n :maxlength=\"maxlength\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-textarea',\n `mint-textarea--${size}`,\n `mint-textarea--resize-${resize}`,\n invalid ? 'mint-textarea--error' : '',\n disabled ? 'mint-textarea--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <div\n v-else-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n invalid ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n invalid ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","export type OptionLike<TValue extends string | number> = {\n value: TValue\n label: string\n}\n\nexport function normalizeOptionInput<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(option: TOption | TValue): TOption {\n if (typeof option === 'object') return option\n\n return {\n value: option,\n label: String(option),\n } as TOption\n}\n\nexport function findOptionByDomValue<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(options: TOption[], value: string): TOption | undefined {\n return options.find(option => String(option.value) === value)\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type SelectionLimitSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface UseSelectionLimitOptions {\n count: SelectionLimitSource<number>\n max?: SelectionLimitSource<number | null | undefined>\n}\n\nexport interface UseSelectionLimitReturn {\n count: ComputedRef<number>\n max: ComputedRef<number | undefined>\n isLimited: ComputedRef<boolean>\n isAtLimit: ComputedRef<boolean>\n canAddMore: ComputedRef<boolean>\n remaining: ComputedRef<number | undefined>\n canAdd: (amount?: number, fromCount?: number) => boolean\n}\n\n/** Shared cap logic for chip, tag, and multi-select controls. */\nexport function useSelectionLimit(options: UseSelectionLimitOptions): UseSelectionLimitReturn {\n const count = computed(() => Math.max(0, Math.floor(toValue(options.count) || 0)))\n const max = computed(() => normalizeMax(toValue(options.max)))\n const isLimited = computed(() => max.value !== undefined)\n const remaining = computed(() => {\n if (max.value === undefined) return undefined\n return Math.max(0, max.value - count.value)\n })\n const isAtLimit = computed(() => remaining.value === 0)\n const canAddMore = computed(() => canAdd(1))\n\n function canAdd(amount = 1, fromCount = count.value): boolean {\n const normalizedAmount = Math.max(0, Math.floor(amount))\n const normalizedCount = Math.max(0, Math.floor(fromCount))\n if (max.value === undefined) return true\n return normalizedCount + normalizedAmount <= max.value\n }\n\n return {\n count,\n max,\n isLimited,\n isAtLimit,\n canAddMore,\n remaining,\n canAdd,\n }\n}\n\nfunction normalizeMax(value: number | null | undefined): number | undefined {\n if (value === null || value === undefined || !Number.isFinite(value)) return undefined\n return Math.max(0, Math.floor(value))\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport { useSelectionLimit, type SelectionLimitSource } from './useSelectionLimit'\n\nexport type ListSelectionValue = string | number\n\nexport type ListSelectionSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type WidenListSelectionValue<TValue extends ListSelectionValue> =\n TValue extends string ? string : TValue extends number ? number : TValue\n\nexport interface UseListSelectionOptions<\n TItem,\n TValue extends ListSelectionValue = ListSelectionValue,\n> {\n selected: ListSelectionSource<readonly TValue[]>\n items?: ListSelectionSource<readonly TItem[]>\n getValue?: (item: TItem) => TValue\n disabled?: ListSelectionSource<boolean | null | undefined>\n max?: SelectionLimitSource<number | null | undefined>\n}\n\nexport interface UseListSelectionReturn<TValue extends ListSelectionValue = ListSelectionValue> {\n selectedValues: ComputedRef<TValue[]>\n selectedSet: ComputedRef<Set<TValue>>\n itemValues: ComputedRef<TValue[]>\n selectedCount: ComputedRef<number>\n itemCount: ComputedRef<number>\n isAllSelected: ComputedRef<boolean>\n isLimited: ComputedRef<boolean>\n isAtLimit: ComputedRef<boolean>\n canAddMore: ComputedRef<boolean>\n remaining: ComputedRef<number | undefined>\n isSelected: (value: TValue) => boolean\n isFullySelected: (values: readonly TValue[]) => boolean\n isPartiallySelected: (values: readonly TValue[]) => boolean\n selectValues: (values: readonly TValue[]) => TValue[]\n toggleValue: (value: TValue) => TValue[]\n toggleValues: (values: readonly TValue[]) => TValue[]\n selectAll: () => TValue[]\n toggleAll: () => TValue[]\n clear: () => TValue[]\n}\n\n/** Shared list-selection state for checkbox lists, sample selectors, and chip selectors. */\nexport function useListSelection<\n TItem = ListSelectionValue,\n TValue extends ListSelectionValue = TItem extends ListSelectionValue ? TItem : ListSelectionValue,\n>(options: UseListSelectionOptions<TItem, TValue>): UseListSelectionReturn<WidenListSelectionValue<TValue>> {\n type ResolvedValue = WidenListSelectionValue<TValue>\n\n const disabled = computed(() => toValue(options.disabled) ?? false)\n const selectedValues = computed<ResolvedValue[]>(() => [...toValue(options.selected)] as ResolvedValue[])\n const selectedSet = computed(() => new Set(selectedValues.value))\n const itemValues = computed<ResolvedValue[]>(() => {\n const items = toValue(options.items) ?? []\n return items.map(item => getItemValue(item, options.getValue) as ResolvedValue)\n })\n\n const selectedCount = computed(() => selectedValues.value.length)\n const itemCount = computed(() => itemValues.value.length)\n const isAllSelected = computed(() => (\n itemValues.value.length > 0 && itemValues.value.every(value => selectedSet.value.has(value))\n ))\n const selectionLimit = useSelectionLimit({\n count: selectedCount,\n max: options.max,\n })\n\n function isSelected(value: ResolvedValue): boolean {\n return selectedSet.value.has(value)\n }\n\n function isFullySelected(values: readonly ResolvedValue[]): boolean {\n return values.length > 0 && values.every(value => selectedSet.value.has(value))\n }\n\n function isPartiallySelected(values: readonly ResolvedValue[]): boolean {\n if (values.length === 0) return false\n const selected = values.filter(value => selectedSet.value.has(value)).length\n return selected > 0 && selected < values.length\n }\n\n function selectValues(values: readonly ResolvedValue[]): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n const missing = uniqueValues(values).filter(value => !selectedSet.value.has(value))\n if (!selectionLimit.canAdd(missing.length)) return selectedValues.value\n return [...selectedValues.value, ...missing]\n }\n\n function toggleValue(value: ResolvedValue): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n if (selectedSet.value.has(value)) {\n return selectedValues.value.filter(selected => selected !== value)\n }\n if (!selectionLimit.canAddMore.value) return selectedValues.value\n return [...selectedValues.value, value]\n }\n\n function toggleValues(values: readonly ResolvedValue[]): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n const unique = uniqueValues(values)\n if (isFullySelected(unique)) {\n const remove = new Set(unique)\n return selectedValues.value.filter(value => !remove.has(value))\n }\n return selectValues(unique)\n }\n\n function selectAll(): ResolvedValue[] {\n return selectValues(itemValues.value)\n }\n\n function toggleAll(): ResolvedValue[] {\n if (isAllSelected.value) return clear()\n return selectAll()\n }\n\n function clear(): ResolvedValue[] {\n return disabled.value ? selectedValues.value : []\n }\n\n return {\n selectedValues,\n selectedSet,\n itemValues,\n selectedCount,\n itemCount,\n isAllSelected,\n isLimited: selectionLimit.isLimited,\n isAtLimit: selectionLimit.isAtLimit,\n canAddMore: selectionLimit.canAddMore,\n remaining: selectionLimit.remaining,\n isSelected,\n isFullySelected,\n isPartiallySelected,\n selectValues,\n toggleValue,\n toggleValues,\n selectAll,\n toggleAll,\n clear,\n }\n}\n\nfunction getItemValue<TItem, TValue extends ListSelectionValue>(\n item: TItem,\n getValue: ((item: TItem) => TValue) | undefined,\n): TValue {\n return getValue ? getValue(item) : item as unknown as TValue\n}\n\nfunction uniqueValues<TValue extends ListSelectionValue>(values: readonly TValue[]): TValue[] {\n return [...new Set(values)]\n}\n","<script setup lang=\"ts\">\n/** BaseSelect with `multiple`: a checkbox chip list with an optional selection cap (`max`). */\nimport { computed } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../../types'\nimport { useListSelection } from '../../composables/useListSelection'\nimport { normalizeOptionInput } from '../../utils/options'\n\ntype MultiOption = SelectOption<OptionPrimitive>\n\ninterface Props {\n modelValue: OptionPrimitive[]\n options: SelectOptionInput[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n max?: number\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select options...',\n disabled: false,\n invalid: false,\n max: undefined,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: OptionPrimitive[]]\n}>()\n\nconst normalizedOptions = computed<MultiOption[]>(() => props.options.map(normalizeOptionInput<OptionPrimitive, MultiOption>))\nconst optionSelection = useListSelection({\n selected: () => props.modelValue,\n items: normalizedOptions,\n getValue: option => option.value,\n disabled: () => props.disabled,\n max: () => props.max,\n})\nconst canSelectMore = optionSelection.canAddMore\n\nfunction isSelected(value: OptionPrimitive): boolean {\n return optionSelection.isSelected(value)\n}\n\nfunction toggleOption(option: MultiOption) {\n if (props.disabled || option.disabled) return\n\n if (isSelected(option.value) || canSelectMore.value) {\n emit('update:modelValue', optionSelection.toggleValue(option.value))\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent, option: MultiOption) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n toggleOption(option)\n }\n}\n\nconst selectedLabels = computed(() => {\n return props.modelValue\n .map(v => normalizedOptions.value.find(o => o.value === v)?.label)\n .filter(Boolean)\n})\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-multi-select',\n `mint-multi-select--${size}`,\n disabled ? 'mint-multi-select--disabled' : '',\n invalid ? 'mint-multi-select--error' : '',\n ]\"\n >\n <div\n v-if=\"modelValue.length === 0\"\n class=\"mint-multi-select__placeholder\"\n >\n {{ placeholder }}\n </div>\n\n <div class=\"mint-multi-select__options\" role=\"group\" :aria-invalid=\"invalid || undefined\">\n <button\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n type=\"button\"\n role=\"checkbox\"\n :aria-checked=\"isSelected(option.value)\"\n :disabled=\"disabled || option.disabled || (!isSelected(option.value) && !canSelectMore)\"\n :class=\"[\n 'mint-multi-select__chip',\n `mint-multi-select__chip--${size}`,\n isSelected(option.value) ? 'mint-multi-select__chip--active' : '',\n option.disabled ? 'mint-multi-select__chip--disabled' : '',\n !isSelected(option.value) && !canSelectMore ? 'mint-multi-select__chip--disabled' : '',\n ]\"\n @click=\"toggleOption(option)\"\n @keydown=\"handleKeydown($event, option)\"\n >\n <svg\n class=\"mint-multi-select__chip-check\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n <span class=\"mint-multi-select__chip-label\">{{ option.label }}</span>\n </button>\n </div>\n\n <div\n v-if=\"modelValue.length > 0\"\n class=\"mint-multi-select__summary\"\n >\n {{ selectedLabels.join(', ') }}\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `multiple`: a checkbox chip list with an optional selection cap (`max`). */\nimport { computed } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../../types'\nimport { useListSelection } from '../../composables/useListSelection'\nimport { normalizeOptionInput } from '../../utils/options'\n\ntype MultiOption = SelectOption<OptionPrimitive>\n\ninterface Props {\n modelValue: OptionPrimitive[]\n options: SelectOptionInput[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n max?: number\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select options...',\n disabled: false,\n invalid: false,\n max: undefined,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: OptionPrimitive[]]\n}>()\n\nconst normalizedOptions = computed<MultiOption[]>(() => props.options.map(normalizeOptionInput<OptionPrimitive, MultiOption>))\nconst optionSelection = useListSelection({\n selected: () => props.modelValue,\n items: normalizedOptions,\n getValue: option => option.value,\n disabled: () => props.disabled,\n max: () => props.max,\n})\nconst canSelectMore = optionSelection.canAddMore\n\nfunction isSelected(value: OptionPrimitive): boolean {\n return optionSelection.isSelected(value)\n}\n\nfunction toggleOption(option: MultiOption) {\n if (props.disabled || option.disabled) return\n\n if (isSelected(option.value) || canSelectMore.value) {\n emit('update:modelValue', optionSelection.toggleValue(option.value))\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent, option: MultiOption) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n toggleOption(option)\n }\n}\n\nconst selectedLabels = computed(() => {\n return props.modelValue\n .map(v => normalizedOptions.value.find(o => o.value === v)?.label)\n .filter(Boolean)\n})\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-multi-select',\n `mint-multi-select--${size}`,\n disabled ? 'mint-multi-select--disabled' : '',\n invalid ? 'mint-multi-select--error' : '',\n ]\"\n >\n <div\n v-if=\"modelValue.length === 0\"\n class=\"mint-multi-select__placeholder\"\n >\n {{ placeholder }}\n </div>\n\n <div class=\"mint-multi-select__options\" role=\"group\" :aria-invalid=\"invalid || undefined\">\n <button\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n type=\"button\"\n role=\"checkbox\"\n :aria-checked=\"isSelected(option.value)\"\n :disabled=\"disabled || option.disabled || (!isSelected(option.value) && !canSelectMore)\"\n :class=\"[\n 'mint-multi-select__chip',\n `mint-multi-select__chip--${size}`,\n isSelected(option.value) ? 'mint-multi-select__chip--active' : '',\n option.disabled ? 'mint-multi-select__chip--disabled' : '',\n !isSelected(option.value) && !canSelectMore ? 'mint-multi-select__chip--disabled' : '',\n ]\"\n @click=\"toggleOption(option)\"\n @keydown=\"handleKeydown($event, option)\"\n >\n <svg\n class=\"mint-multi-select__chip-check\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n <span class=\"mint-multi-select__chip-label\">{{ option.label }}</span>\n </button>\n </div>\n\n <div\n v-if=\"modelValue.length > 0\"\n class=\"mint-multi-select__summary\"\n >\n {{ selectedLabels.join(', ') }}\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `searchable`: a single-select listbox with a search field, descriptions, disabled reasons, and custom slots. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { normalizeOptionInput } from '../../utils/options'\n\ninterface Props {\n modelValue?: string | number | null\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n searchPlaceholder?: string\n noResultsText?: string\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n invalid?: boolean\n /** Id of the visible label; the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select an option',\n searchPlaceholder: 'Search options…',\n noResultsText: 'No matching options',\n size: 'md',\n disabled: false,\n invalid: false,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focused trigger.\nconst attrs = useAttrs()\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\ndefineSlots<{\n option?: (props: { option: SelectOption<string | number>; selected: boolean; active: boolean }) => unknown\n footer?: () => unknown\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-searchable-select-${id}`\nconst triggerId = `${listboxId}-trigger`\nconst root = ref<HTMLElement | null>(null)\nconst trigger = ref<HTMLButtonElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput),\n)\nconst selectedOption = computed(() =>\n normalizedOptions.value.find(option => option.value === props.modelValue),\n)\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option =>\n [option.label, option.description, option.meta, option.disabledReason]\n .some(value => value?.toLocaleLowerCase().includes(needle)),\n )\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction firstEnabledIndex(options = visibleOptions.value): number {\n return options.findIndex(option => !option.disabled)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled) return\n query.value = ''\n open.value = true\n activeIndex.value = firstEnabledIndex(normalizedOptions.value)\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n trigger.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const enabled = visibleOptions.value\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled)\n if (enabled.length === 0) return\n const current = enabled.findIndex(({ index }) => index === activeIndex.value)\n const next = current < 0\n ? (direction === 1 ? 0 : enabled.length - 1)\n : (current + direction + enabled.length) % enabled.length\n activeIndex.value = enabled[next]!.index\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction select(option: SelectOption<string | number>): void {\n if (option.disabled) return\n emit('update:modelValue', option.value)\n void closePanel(true)\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Home') activeIndex.value = firstEnabledIndex()\n else if (event.key === 'End') {\n for (let index = visibleOptions.value.length - 1; index >= 0; index--) {\n if (!visibleOptions.value[index]?.disabled) {\n activeIndex.value = index\n break\n }\n }\n } else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) select(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else return\n event.preventDefault()\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n event.preventDefault()\n void openPanel().then(() => {\n if (event.key === 'ArrowUp') moveActive(-1)\n })\n}\n\nwatch(visibleOptions, options => { activeIndex.value = firstEnabledIndex(options) })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-searchable-select', `mint-searchable-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <button\n v-bind=\"triggerAttrs\"\n :id=\"triggerId\"\n ref=\"trigger\"\n type=\"button\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby ? `${ariaLabelledby} ${triggerId}` : undefined\"\n :class=\"['mint-searchable-select__trigger', { 'mint-searchable-select__trigger--error': invalid }]\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n aria-haspopup=\"listbox\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown=\"handleTriggerKeydown\"\n >\n <span :class=\"['mint-searchable-select__value', { 'mint-searchable-select__value--placeholder': !selectedOption }]\">\n {{ selectedOption?.label ?? placeholder }}\n </span>\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.75\" d=\"m6 8 4 4 4-4\" />\n </svg>\n </button>\n\n <div v-if=\"open\" class=\"mint-popover mint-searchable-select__panel\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n :placeholder=\"searchPlaceholder\"\n :aria-label=\"searchPlaceholder\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-searchable-select__option\"\n :class=\"{\n 'mint-menu-item--active mint-searchable-select__option--active': activeIndex === index,\n 'mint-menu-item--selected mint-searchable-select__option--selected': modelValue === option.value,\n 'mint-searchable-select__option--disabled': option.disabled,\n }\"\n :aria-selected=\"modelValue === option.value\"\n :aria-disabled=\"option.disabled || undefined\"\n @mousedown.prevent\n @mouseenter=\"!option.disabled && (activeIndex = index)\"\n @click=\"select(option)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"modelValue === option.value\" :active=\"activeIndex === index\">\n <span class=\"mint-menu-item__text mint-searchable-select__option-text\">\n <span class=\"mint-menu-item__label mint-searchable-select__option-label\">{{ option.label }}</span>\n <span v-if=\"option.disabled ? option.disabledReason || option.description : option.description\" class=\"mint-menu-item__description mint-searchable-select__option-description\">\n {{ option.disabled ? option.disabledReason || option.description : option.description }}\n </span>\n </span>\n <span v-if=\"option.meta\" class=\"mint-menu-item__meta mint-searchable-select__option-meta\">{{ option.meta }}</span>\n <svg class=\"mint-menu-item__check mint-searchable-select__check\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 10 3 3 7-7\" />\n </svg>\n </slot>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">{{ noResultsText }}</li>\n </ul>\n\n <div v-if=\"$slots.footer\" class=\"mint-searchable-select__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `searchable`: a single-select listbox with a search field, descriptions, disabled reasons, and custom slots. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { normalizeOptionInput } from '../../utils/options'\n\ninterface Props {\n modelValue?: string | number | null\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n searchPlaceholder?: string\n noResultsText?: string\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n invalid?: boolean\n /** Id of the visible label; the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select an option',\n searchPlaceholder: 'Search options…',\n noResultsText: 'No matching options',\n size: 'md',\n disabled: false,\n invalid: false,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focused trigger.\nconst attrs = useAttrs()\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\ndefineSlots<{\n option?: (props: { option: SelectOption<string | number>; selected: boolean; active: boolean }) => unknown\n footer?: () => unknown\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-searchable-select-${id}`\nconst triggerId = `${listboxId}-trigger`\nconst root = ref<HTMLElement | null>(null)\nconst trigger = ref<HTMLButtonElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput),\n)\nconst selectedOption = computed(() =>\n normalizedOptions.value.find(option => option.value === props.modelValue),\n)\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option =>\n [option.label, option.description, option.meta, option.disabledReason]\n .some(value => value?.toLocaleLowerCase().includes(needle)),\n )\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction firstEnabledIndex(options = visibleOptions.value): number {\n return options.findIndex(option => !option.disabled)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled) return\n query.value = ''\n open.value = true\n activeIndex.value = firstEnabledIndex(normalizedOptions.value)\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n trigger.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const enabled = visibleOptions.value\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled)\n if (enabled.length === 0) return\n const current = enabled.findIndex(({ index }) => index === activeIndex.value)\n const next = current < 0\n ? (direction === 1 ? 0 : enabled.length - 1)\n : (current + direction + enabled.length) % enabled.length\n activeIndex.value = enabled[next]!.index\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction select(option: SelectOption<string | number>): void {\n if (option.disabled) return\n emit('update:modelValue', option.value)\n void closePanel(true)\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Home') activeIndex.value = firstEnabledIndex()\n else if (event.key === 'End') {\n for (let index = visibleOptions.value.length - 1; index >= 0; index--) {\n if (!visibleOptions.value[index]?.disabled) {\n activeIndex.value = index\n break\n }\n }\n } else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) select(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else return\n event.preventDefault()\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n event.preventDefault()\n void openPanel().then(() => {\n if (event.key === 'ArrowUp') moveActive(-1)\n })\n}\n\nwatch(visibleOptions, options => { activeIndex.value = firstEnabledIndex(options) })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-searchable-select', `mint-searchable-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <button\n v-bind=\"triggerAttrs\"\n :id=\"triggerId\"\n ref=\"trigger\"\n type=\"button\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby ? `${ariaLabelledby} ${triggerId}` : undefined\"\n :class=\"['mint-searchable-select__trigger', { 'mint-searchable-select__trigger--error': invalid }]\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n aria-haspopup=\"listbox\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown=\"handleTriggerKeydown\"\n >\n <span :class=\"['mint-searchable-select__value', { 'mint-searchable-select__value--placeholder': !selectedOption }]\">\n {{ selectedOption?.label ?? placeholder }}\n </span>\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.75\" d=\"m6 8 4 4 4-4\" />\n </svg>\n </button>\n\n <div v-if=\"open\" class=\"mint-popover mint-searchable-select__panel\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n :placeholder=\"searchPlaceholder\"\n :aria-label=\"searchPlaceholder\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-searchable-select__option\"\n :class=\"{\n 'mint-menu-item--active mint-searchable-select__option--active': activeIndex === index,\n 'mint-menu-item--selected mint-searchable-select__option--selected': modelValue === option.value,\n 'mint-searchable-select__option--disabled': option.disabled,\n }\"\n :aria-selected=\"modelValue === option.value\"\n :aria-disabled=\"option.disabled || undefined\"\n @mousedown.prevent\n @mouseenter=\"!option.disabled && (activeIndex = index)\"\n @click=\"select(option)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"modelValue === option.value\" :active=\"activeIndex === index\">\n <span class=\"mint-menu-item__text mint-searchable-select__option-text\">\n <span class=\"mint-menu-item__label mint-searchable-select__option-label\">{{ option.label }}</span>\n <span v-if=\"option.disabled ? option.disabledReason || option.description : option.description\" class=\"mint-menu-item__description mint-searchable-select__option-description\">\n {{ option.disabled ? option.disabledReason || option.description : option.description }}\n </span>\n </span>\n <span v-if=\"option.meta\" class=\"mint-menu-item__meta mint-searchable-select__option-meta\">{{ option.meta }}</span>\n <svg class=\"mint-menu-item__check mint-searchable-select__check\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 10 3 3 7-7\" />\n </svg>\n </slot>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">{{ noResultsText }}</li>\n </ul>\n\n <div v-if=\"$slots.footer\" class=\"mint-searchable-select__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"M extends boolean = false\">\n/**\n * Select one or several options.\n * Default: a native `<select>`. `searchable`: a listbox with a search field and the `#option` / `#footer` slots.\n * `multiple`: a checkbox chip list bound to an array, capped by `max`.\n *\n * @example\n * ```vue\n * <BaseSelect v-model=\"method\" :options=\"methods\" />\n * <BaseSelect v-model=\"template\" :options=\"templates\" searchable placeholder=\"Select template…\" />\n * <BaseSelect v-model=\"instrumentIds\" :options=\"instruments\" multiple :max=\"3\" />\n * ```\n */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\nimport SelectMultipleInternal from './internal/SelectMultipleInternal.vue'\nimport SelectSearchableInternal from './internal/SelectSearchableInternal.vue'\n\ndefineOptions({ inheritAttrs: false })\n\n\nconst props = withDefaults(defineProps<{\n /** The selected value; an array with `multiple`. */\n modelValue?: (M extends true ? OptionPrimitive[] : OptionPrimitive) | null\n options: SelectOptionInput[]\n /** Bind an array and pick several options (chip list). */\n multiple?: M\n /** Single selection in a listbox with a search field. Ignored with `multiple`. */\n searchable?: boolean\n /** Most options a `multiple` select accepts. */\n max?: number\n placeholder?: string\n /** Search field placeholder (`searchable`). */\n searchPlaceholder?: string\n /** Text shown when the search matches no option (`searchable`). */\n noResultsText?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n /** Id of the visible label (`searchable`); the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n}>(), {\n modelValue: null,\n multiple: undefined,\n searchable: false,\n max: undefined,\n placeholder: undefined,\n searchPlaceholder: undefined,\n noResultsText: undefined,\n disabled: false,\n invalid: false,\n size: 'md',\n ariaDescribedby: undefined,\n ariaLabelledby: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: M extends true ? OptionPrimitive[] : OptionPrimitive]\n}>()\n\ndefineSlots<{\n /** `searchable` only: custom option row. */\n option?: (props: { option: SelectOption<OptionPrimitive>; selected: boolean; active: boolean }) => unknown\n /** `searchable` only: content under the option list. */\n footer?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst normalizedOptions = computed<SelectOption<OptionPrimitive>[]>(() =>\n props.options.map(option => normalizeOptionInput<OptionPrimitive, SelectOption<OptionPrimitive>>(option)),\n)\n\n// `multiple` has the generic type `M`, so Vue declares no runtime Boolean type for it and\n// does not cast the bare attribute: `<BaseSelect multiple>` arrives as ''.\nconst isMultiple = computed(() => props.multiple === true || (props.multiple as unknown) === '')\n\nconst multipleValue = computed<OptionPrimitive[]>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? value : []\n})\nconst singleValue = computed<OptionPrimitive | null>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? null : (value as OptionPrimitive | null)\n})\n\nfunction update(value: OptionPrimitive | OptionPrimitive[]) {\n emit('update:modelValue', value as M extends true ? OptionPrimitive[] : OptionPrimitive)\n}\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n update(option?.value ?? target.value)\n}\n</script>\n\n<template>\n <SelectMultipleInternal\n v-if=\"isMultiple\"\n v-bind=\"attrs\"\n :model-value=\"multipleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :max=\"max\"\n :size=\"size\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n />\n <SelectSearchableInternal\n v-else-if=\"searchable\"\n v-bind=\"attrs\"\n :model-value=\"singleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :search-placeholder=\"searchPlaceholder\"\n :no-results-text=\"noResultsText\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n >\n <template v-if=\"$slots.option\" #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n </SelectSearchableInternal>\n <div v-else v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"singleValue ?? ''\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n invalid ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"M extends boolean = false\">\n/**\n * Select one or several options.\n * Default: a native `<select>`. `searchable`: a listbox with a search field and the `#option` / `#footer` slots.\n * `multiple`: a checkbox chip list bound to an array, capped by `max`.\n *\n * @example\n * ```vue\n * <BaseSelect v-model=\"method\" :options=\"methods\" />\n * <BaseSelect v-model=\"template\" :options=\"templates\" searchable placeholder=\"Select template…\" />\n * <BaseSelect v-model=\"instrumentIds\" :options=\"instruments\" multiple :max=\"3\" />\n * ```\n */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\nimport SelectMultipleInternal from './internal/SelectMultipleInternal.vue'\nimport SelectSearchableInternal from './internal/SelectSearchableInternal.vue'\n\ndefineOptions({ inheritAttrs: false })\n\n\nconst props = withDefaults(defineProps<{\n /** The selected value; an array with `multiple`. */\n modelValue?: (M extends true ? OptionPrimitive[] : OptionPrimitive) | null\n options: SelectOptionInput[]\n /** Bind an array and pick several options (chip list). */\n multiple?: M\n /** Single selection in a listbox with a search field. Ignored with `multiple`. */\n searchable?: boolean\n /** Most options a `multiple` select accepts. */\n max?: number\n placeholder?: string\n /** Search field placeholder (`searchable`). */\n searchPlaceholder?: string\n /** Text shown when the search matches no option (`searchable`). */\n noResultsText?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n /** Id of the visible label (`searchable`); the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n}>(), {\n modelValue: null,\n multiple: undefined,\n searchable: false,\n max: undefined,\n placeholder: undefined,\n searchPlaceholder: undefined,\n noResultsText: undefined,\n disabled: false,\n invalid: false,\n size: 'md',\n ariaDescribedby: undefined,\n ariaLabelledby: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: M extends true ? OptionPrimitive[] : OptionPrimitive]\n}>()\n\ndefineSlots<{\n /** `searchable` only: custom option row. */\n option?: (props: { option: SelectOption<OptionPrimitive>; selected: boolean; active: boolean }) => unknown\n /** `searchable` only: content under the option list. */\n footer?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst normalizedOptions = computed<SelectOption<OptionPrimitive>[]>(() =>\n props.options.map(option => normalizeOptionInput<OptionPrimitive, SelectOption<OptionPrimitive>>(option)),\n)\n\n// `multiple` has the generic type `M`, so Vue declares no runtime Boolean type for it and\n// does not cast the bare attribute: `<BaseSelect multiple>` arrives as ''.\nconst isMultiple = computed(() => props.multiple === true || (props.multiple as unknown) === '')\n\nconst multipleValue = computed<OptionPrimitive[]>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? value : []\n})\nconst singleValue = computed<OptionPrimitive | null>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? null : (value as OptionPrimitive | null)\n})\n\nfunction update(value: OptionPrimitive | OptionPrimitive[]) {\n emit('update:modelValue', value as M extends true ? OptionPrimitive[] : OptionPrimitive)\n}\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n update(option?.value ?? target.value)\n}\n</script>\n\n<template>\n <SelectMultipleInternal\n v-if=\"isMultiple\"\n v-bind=\"attrs\"\n :model-value=\"multipleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :max=\"max\"\n :size=\"size\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n />\n <SelectSearchableInternal\n v-else-if=\"searchable\"\n v-bind=\"attrs\"\n :model-value=\"singleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :search-placeholder=\"searchPlaceholder\"\n :no-results-text=\"noResultsText\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n >\n <template v-if=\"$slots.option\" #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n </SelectSearchableInternal>\n <div v-else v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"singleValue ?? ''\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n invalid ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Floating tooltip using @floating-ui with auto-flip, delay, optional keyboard shortcut badge, and body Teleport. */\nimport { ref, onBeforeUnmount, nextTick } from 'vue'\nimport { computePosition, flip, offset, shift, type Placement } from '@floating-ui/dom'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n text: string\n position?: 'top' | 'bottom' | 'left' | 'right'\n delay?: number\n shortcut?: string\n maxWidth?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n position: 'top',\n delay: 200,\n shortcut: undefined,\n maxWidth: undefined,\n})\n\nconst tooltipId = `mint-tooltip-${Math.random().toString(36).slice(2, 9)}`\nconst visible = ref(false)\nconst actualPlacement = ref<Placement>(props.position)\nconst triggerRef = ref<HTMLElement | null>(null)\nconst contentRef = ref<HTMLElement | null>(null)\nconst coords = ref({ top: '0px', left: '0px' })\nlet timeoutId: ReturnType<typeof setTimeout> | undefined\n\nasync function updatePosition() {\n if (!triggerRef.value || !contentRef.value) return\n\n const { x, y, placement } = await computePosition(triggerRef.value, contentRef.value, {\n placement: props.position,\n middleware: [\n offset(6),\n flip(),\n shift({ padding: 8 }),\n ],\n })\n\n coords.value = { top: `${y}px`, left: `${x}px` }\n actualPlacement.value = placement\n}\n\nuseEventListener(() => window, 'scroll', updatePosition, {\n passive: true,\n capture: true,\n enabled: visible,\n})\nuseEventListener(() => window, 'resize', updatePosition, { enabled: visible })\n\nasync function show() {\n timeoutId = setTimeout(async () => {\n visible.value = true\n await nextTick()\n await updatePosition()\n }, props.delay)\n}\n\nfunction hide() {\n clearTimeout(timeoutId)\n timeoutId = undefined\n visible.value = false\n}\n\nonBeforeUnmount(() => {\n clearTimeout(timeoutId)\n})\n\nfunction resolvedMaxWidth(value: string | number | undefined): string | undefined {\n if (value === undefined) return undefined\n return typeof value === 'number' ? `${value}px` : value\n}\n</script>\n\n<template>\n <span\n ref=\"triggerRef\"\n class=\"mint-tooltip\"\n :aria-describedby=\"visible ? tooltipId : undefined\"\n @mouseenter=\"show\"\n @mouseleave=\"hide\"\n @focusin=\"show\"\n @focusout=\"hide\"\n >\n <slot />\n <Teleport to=\"body\">\n <span\n v-if=\"visible\"\n :id=\"tooltipId\"\n ref=\"contentRef\"\n :class=\"[\n 'mint-tooltip__content',\n `mint-tooltip__content--${actualPlacement}`,\n maxWidth ? 'mint-tooltip__content--multiline' : '',\n ]\"\n :style=\"{\n top: coords.top,\n left: coords.left,\n maxWidth: resolvedMaxWidth(maxWidth),\n }\"\n role=\"tooltip\"\n >\n <span class=\"mint-tooltip__body\">{{ text }}</span>\n <kbd v-if=\"shortcut\" class=\"mint-tooltip__shortcut\">{{ shortcut }}</kbd>\n </span>\n </Teleport>\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** Floating tooltip using @floating-ui with auto-flip, delay, optional keyboard shortcut badge, and body Teleport. */\nimport { ref, onBeforeUnmount, nextTick } from 'vue'\nimport { computePosition, flip, offset, shift, type Placement } from '@floating-ui/dom'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n text: string\n position?: 'top' | 'bottom' | 'left' | 'right'\n delay?: number\n shortcut?: string\n maxWidth?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n position: 'top',\n delay: 200,\n shortcut: undefined,\n maxWidth: undefined,\n})\n\nconst tooltipId = `mint-tooltip-${Math.random().toString(36).slice(2, 9)}`\nconst visible = ref(false)\nconst actualPlacement = ref<Placement>(props.position)\nconst triggerRef = ref<HTMLElement | null>(null)\nconst contentRef = ref<HTMLElement | null>(null)\nconst coords = ref({ top: '0px', left: '0px' })\nlet timeoutId: ReturnType<typeof setTimeout> | undefined\n\nasync function updatePosition() {\n if (!triggerRef.value || !contentRef.value) return\n\n const { x, y, placement } = await computePosition(triggerRef.value, contentRef.value, {\n placement: props.position,\n middleware: [\n offset(6),\n flip(),\n shift({ padding: 8 }),\n ],\n })\n\n coords.value = { top: `${y}px`, left: `${x}px` }\n actualPlacement.value = placement\n}\n\nuseEventListener(() => window, 'scroll', updatePosition, {\n passive: true,\n capture: true,\n enabled: visible,\n})\nuseEventListener(() => window, 'resize', updatePosition, { enabled: visible })\n\nasync function show() {\n timeoutId = setTimeout(async () => {\n visible.value = true\n await nextTick()\n await updatePosition()\n }, props.delay)\n}\n\nfunction hide() {\n clearTimeout(timeoutId)\n timeoutId = undefined\n visible.value = false\n}\n\nonBeforeUnmount(() => {\n clearTimeout(timeoutId)\n})\n\nfunction resolvedMaxWidth(value: string | number | undefined): string | undefined {\n if (value === undefined) return undefined\n return typeof value === 'number' ? `${value}px` : value\n}\n</script>\n\n<template>\n <span\n ref=\"triggerRef\"\n class=\"mint-tooltip\"\n :aria-describedby=\"visible ? tooltipId : undefined\"\n @mouseenter=\"show\"\n @mouseleave=\"hide\"\n @focusin=\"show\"\n @focusout=\"hide\"\n >\n <slot />\n <Teleport to=\"body\">\n <span\n v-if=\"visible\"\n :id=\"tooltipId\"\n ref=\"contentRef\"\n :class=\"[\n 'mint-tooltip__content',\n `mint-tooltip__content--${actualPlacement}`,\n maxWidth ? 'mint-tooltip__content--multiline' : '',\n ]\"\n :style=\"{\n top: coords.top,\n left: coords.left,\n maxWidth: resolvedMaxWidth(maxWidth),\n }\"\n role=\"tooltip\"\n >\n <span class=\"mint-tooltip__body\">{{ text }}</span>\n <kbd v-if=\"shortcut\" class=\"mint-tooltip__shortcut\">{{ shortcut }}</kbd>\n </span>\n </Teleport>\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** BaseCheckbox with `type=\"switch\"`: an on/off switch with label, size, and keyboard interaction support. */\nimport Tooltip from '../Tooltip.vue'\n\ninterface Props {\n modelValue?: boolean\n label?: string\n /** Accessible switch name; defaults to the visual label, then \"Toggle\". */\n ariaLabel?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n reverse?: boolean\n layout?: 'inline' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false,\n size: 'md',\n reverse: false,\n layout: 'inline',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction toggle() {\n if (!props.disabled) {\n emit('update:modelValue', !props.modelValue)\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n toggle()\n }\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-toggle',\n `mint-toggle--${layout}`,\n reverse ? 'mint-toggle--reverse' : '',\n disabled ? 'mint-toggle--disabled' : '',\n modelValue ? 'mint-toggle--checked' : '',\n ]\"\n @click=\"toggle\"\n >\n <span\n v-if=\"layout === 'row' && icon\"\n class=\"mint-toggle__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(icon)\"\n class=\"mint-toggle__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(icon)\">\n <path v-for=\"(d, i) in icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"icon\" />\n </svg>\n <span v-else class=\"mint-toggle__row-text-icon\">{{ icon }}</span>\n </span>\n <span\n v-if=\"layout === 'row' && label\"\n class=\"mint-toggle__copy\"\n >\n <Tooltip\n v-if=\"description\"\n :text=\"description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-toggle__label', `mint-toggle__label--${size}`, 'mint-toggle__label--tooltip']\">\n {{ label }}\n </span>\n </Tooltip>\n <span\n v-else\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </span>\n <div\n role=\"switch\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-checked=\"modelValue\"\n :aria-label=\"ariaLabel || label || 'Toggle'\"\n :class=\"[\n 'mint-toggle__track',\n `mint-toggle__track--${size}`,\n modelValue ? 'mint-toggle__track--on' : 'mint-toggle__track--off',\n ]\"\n @keydown=\"handleKeydown\"\n >\n <span :class=\"['mint-toggle__knob', `mint-toggle__knob--${size}`]\" />\n </div>\n <span\n v-if=\"label && layout !== 'row'\"\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseCheckbox with `type=\"switch\"`: an on/off switch with label, size, and keyboard interaction support. */\nimport Tooltip from '../Tooltip.vue'\n\ninterface Props {\n modelValue?: boolean\n label?: string\n /** Accessible switch name; defaults to the visual label, then \"Toggle\". */\n ariaLabel?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n reverse?: boolean\n layout?: 'inline' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false,\n size: 'md',\n reverse: false,\n layout: 'inline',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction toggle() {\n if (!props.disabled) {\n emit('update:modelValue', !props.modelValue)\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n toggle()\n }\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-toggle',\n `mint-toggle--${layout}`,\n reverse ? 'mint-toggle--reverse' : '',\n disabled ? 'mint-toggle--disabled' : '',\n modelValue ? 'mint-toggle--checked' : '',\n ]\"\n @click=\"toggle\"\n >\n <span\n v-if=\"layout === 'row' && icon\"\n class=\"mint-toggle__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(icon)\"\n class=\"mint-toggle__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(icon)\">\n <path v-for=\"(d, i) in icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"icon\" />\n </svg>\n <span v-else class=\"mint-toggle__row-text-icon\">{{ icon }}</span>\n </span>\n <span\n v-if=\"layout === 'row' && label\"\n class=\"mint-toggle__copy\"\n >\n <Tooltip\n v-if=\"description\"\n :text=\"description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-toggle__label', `mint-toggle__label--${size}`, 'mint-toggle__label--tooltip']\">\n {{ label }}\n </span>\n </Tooltip>\n <span\n v-else\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </span>\n <div\n role=\"switch\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-checked=\"modelValue\"\n :aria-label=\"ariaLabel || label || 'Toggle'\"\n :class=\"[\n 'mint-toggle__track',\n `mint-toggle__track--${size}`,\n modelValue ? 'mint-toggle__track--on' : 'mint-toggle__track--off',\n ]\"\n @keydown=\"handleKeydown\"\n >\n <span :class=\"['mint-toggle__knob', `mint-toggle__knob--${size}`]\" />\n </div>\n <span\n v-if=\"label && layout !== 'row'\"\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled checkbox with an optional label, size variants, and disabled state.\n * `type=\"switch\"` renders an on/off switch; `layout=\"row\"` renders a full-width settings row.\n *\n * @example\n * ```vue\n * <BaseCheckbox v-model=\"agree\" label=\"I agree\" />\n * <BaseCheckbox v-model=\"enabled\" type=\"switch\" label=\"Enable auto-update\" />\n * ```\n */\nimport Tooltip from './Tooltip.vue'\nimport CheckboxSwitchInternal from './internal/CheckboxSwitchInternal.vue'\n\ninterface Props {\n modelValue?: boolean\n /** `checkbox` (default) or an on/off `switch`. */\n type?: 'checkbox' | 'switch'\n /** Partially checked (e.g. select-all over a partial selection); sets `aria-checked=\"mixed\"`. */\n indeterminate?: boolean\n /** Accessible name for the native input when no visible `label` is rendered (e.g. table rows). */\n ariaLabel?: string\n label?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n layout?: 'inline' | 'row'\n /** Switch only: place the switch before the label. */\n reverse?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n indeterminate: false,\n disabled: false,\n type: 'checkbox',\n size: 'md',\n layout: 'inline',\n reverse: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.checked)\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <CheckboxSwitchInternal\n v-if=\"props.type === 'switch'\"\n :model-value=\"props.modelValue\"\n :label=\"props.label\"\n :aria-label=\"props.ariaLabel\"\n :description=\"props.description\"\n :icon=\"props.icon\"\n :icon-color=\"props.iconColor\"\n :icon-bg=\"props.iconBg\"\n :disabled=\"props.disabled\"\n :size=\"props.size\"\n :reverse=\"props.reverse\"\n :layout=\"props.layout\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n />\n <label\n v-else\n :class=\"[\n 'mint-checkbox',\n `mint-checkbox--${props.layout}`,\n props.disabled ? 'mint-checkbox--disabled' : '',\n props.modelValue ? 'mint-checkbox--checked' : '',\n ]\"\n >\n <span\n v-if=\"props.layout === 'row' && props.icon\"\n class=\"mint-checkbox__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(props.icon)\"\n class=\"mint-checkbox__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(props.icon)\">\n <path v-for=\"(d, i) in props.icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"props.icon\" />\n </svg>\n <span v-else class=\"mint-checkbox__row-text-icon\">{{ props.icon }}</span>\n </span>\n <span\n v-if=\"props.layout === 'row' && props.label\"\n class=\"mint-checkbox__copy\"\n >\n <Tooltip\n v-if=\"props.description\"\n :text=\"props.description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`, 'mint-checkbox__label--tooltip']\">\n {{ props.label }}\n </span>\n </Tooltip>\n <span v-else :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </span>\n <div class=\"mint-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n :checked=\"props.modelValue\"\n :indeterminate=\"props.indeterminate\"\n :aria-checked=\"props.indeterminate ? 'mixed' : undefined\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel || props.label || 'Checkbox'\"\n class=\"mint-checkbox__native\"\n @change=\"handleChange\"\n />\n <div\n :class=\"[\n 'mint-checkbox__box',\n `mint-checkbox__box--${props.size}`,\n props.modelValue && !props.indeterminate ? 'mint-checkbox__box--checked' : '',\n props.indeterminate ? 'mint-checkbox__box--indeterminate' : '',\n ]\"\n >\n <svg\n v-if=\"props.indeterminate\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 16 16\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-width=\"2.2\" d=\"M4 8h8\" />\n </svg>\n <svg\n v-else-if=\"props.modelValue\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"3\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <span v-if=\"props.label && props.layout !== 'row'\" :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </label>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled checkbox with an optional label, size variants, and disabled state.\n * `type=\"switch\"` renders an on/off switch; `layout=\"row\"` renders a full-width settings row.\n *\n * @example\n * ```vue\n * <BaseCheckbox v-model=\"agree\" label=\"I agree\" />\n * <BaseCheckbox v-model=\"enabled\" type=\"switch\" label=\"Enable auto-update\" />\n * ```\n */\nimport Tooltip from './Tooltip.vue'\nimport CheckboxSwitchInternal from './internal/CheckboxSwitchInternal.vue'\n\ninterface Props {\n modelValue?: boolean\n /** `checkbox` (default) or an on/off `switch`. */\n type?: 'checkbox' | 'switch'\n /** Partially checked (e.g. select-all over a partial selection); sets `aria-checked=\"mixed\"`. */\n indeterminate?: boolean\n /** Accessible name for the native input when no visible `label` is rendered (e.g. table rows). */\n ariaLabel?: string\n label?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n layout?: 'inline' | 'row'\n /** Switch only: place the switch before the label. */\n reverse?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n indeterminate: false,\n disabled: false,\n type: 'checkbox',\n size: 'md',\n layout: 'inline',\n reverse: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.checked)\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <CheckboxSwitchInternal\n v-if=\"props.type === 'switch'\"\n :model-value=\"props.modelValue\"\n :label=\"props.label\"\n :aria-label=\"props.ariaLabel\"\n :description=\"props.description\"\n :icon=\"props.icon\"\n :icon-color=\"props.iconColor\"\n :icon-bg=\"props.iconBg\"\n :disabled=\"props.disabled\"\n :size=\"props.size\"\n :reverse=\"props.reverse\"\n :layout=\"props.layout\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n />\n <label\n v-else\n :class=\"[\n 'mint-checkbox',\n `mint-checkbox--${props.layout}`,\n props.disabled ? 'mint-checkbox--disabled' : '',\n props.modelValue ? 'mint-checkbox--checked' : '',\n ]\"\n >\n <span\n v-if=\"props.layout === 'row' && props.icon\"\n class=\"mint-checkbox__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(props.icon)\"\n class=\"mint-checkbox__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(props.icon)\">\n <path v-for=\"(d, i) in props.icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"props.icon\" />\n </svg>\n <span v-else class=\"mint-checkbox__row-text-icon\">{{ props.icon }}</span>\n </span>\n <span\n v-if=\"props.layout === 'row' && props.label\"\n class=\"mint-checkbox__copy\"\n >\n <Tooltip\n v-if=\"props.description\"\n :text=\"props.description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`, 'mint-checkbox__label--tooltip']\">\n {{ props.label }}\n </span>\n </Tooltip>\n <span v-else :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </span>\n <div class=\"mint-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n :checked=\"props.modelValue\"\n :indeterminate=\"props.indeterminate\"\n :aria-checked=\"props.indeterminate ? 'mixed' : undefined\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel || props.label || 'Checkbox'\"\n class=\"mint-checkbox__native\"\n @change=\"handleChange\"\n />\n <div\n :class=\"[\n 'mint-checkbox__box',\n `mint-checkbox__box--${props.size}`,\n props.modelValue && !props.indeterminate ? 'mint-checkbox__box--checked' : '',\n props.indeterminate ? 'mint-checkbox__box--indeterminate' : '',\n ]\"\n >\n <svg\n v-if=\"props.indeterminate\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 16 16\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-width=\"2.2\" d=\"M4 8h8\" />\n </svg>\n <svg\n v-else-if=\"props.modelValue\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"3\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <span v-if=\"props.label && props.layout !== 'row'\" :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </label>\n</template>\n","import { nextTick } from 'vue'\n\nexport interface UseRovingFocusOptions {\n /** Selectable item ids, in DOM order. Already excludes items skipped entirely (e.g. disabled tabs). */\n ids: () => string[]\n /** The id that is currently active/selected. */\n activeId: () => string | undefined\n /** Activates an id (e.g. emit `update:modelValue`). The composable focuses the matching element afterward. */\n activate: (id: string) => void\n /** Returns the focusable element for an id, queried lazily so it reflects the post-activation DOM. */\n getElement: (id: string) => HTMLElement | null | undefined\n /** Arrow-key axis: `'horizontal'` (Left/Right, default) or `'vertical'` (Up/Down). */\n orientation?: 'horizontal' | 'vertical'\n}\n\nexport interface UseRovingFocusReturn {\n /** Bind to each item's `@keydown`. */\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * WAI-ARIA roving-tabindex navigation with automatic activation (the tabs pattern):\n * Left/Right (or Up/Down when `orientation` is `'vertical'`) move to the adjacent item\n * and activate it immediately, wrapping past the ends; Home/End jump to the first/last\n * item. Only the active item should carry `tabindex=\"0\"`; give every other item\n * `tabindex=\"-1\"`. Used by BaseTabs.\n */\nexport function useRovingFocus(options: UseRovingFocusOptions): UseRovingFocusReturn {\n const orientation = options.orientation ?? 'horizontal'\n const prevKey = orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'\n const nextKey = orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'\n\n function moveTo(id: string | undefined) {\n if (id === undefined) return\n options.activate(id)\n void nextTick(() => options.getElement(id)?.focus())\n }\n\n function handleKeydown(event: KeyboardEvent) {\n const ids = options.ids()\n if (ids.length === 0) return\n const currentIndex = ids.indexOf(options.activeId() ?? '')\n\n if (event.key === 'Home') {\n event.preventDefault()\n moveTo(ids[0])\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n moveTo(ids[ids.length - 1])\n return\n }\n if (event.key === prevKey) {\n event.preventDefault()\n moveTo(ids[currentIndex <= 0 ? ids.length - 1 : currentIndex - 1])\n return\n }\n if (event.key === nextKey) {\n event.preventDefault()\n moveTo(ids[currentIndex === -1 || currentIndex >= ids.length - 1 ? 0 : currentIndex + 1])\n }\n }\n\n return { handleKeydown }\n}\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\nimport type { Tone } from '../types'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n tone?: Tone\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n tone: 'neutral',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${tone}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${tone}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\nimport type { Tone } from '../types'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n tone?: Tone\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n tone: 'neutral',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${tone}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${tone}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Wraps a form control with a label, optional hint text, and validation error display. */\nimport { computed } from 'vue'\n\ninterface Props {\n label?: string\n error?: string\n hint?: string\n required?: boolean\n showOptional?: boolean\n htmlFor?: string\n /** Prefix for the label (`-label`), error and hint ids. */\n fieldId?: string\n /** `row` puts the label left and the control in a fixed 7.5rem column. Use for numbers, toggles, short enums. */\n layout?: 'stacked' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layout: 'stacked',\n})\n\nconst errorId = computed(() =>\n props.error && props.fieldId ? `${props.fieldId}-error` : undefined\n)\n\nconst hintId = computed(() =>\n !props.error && props.hint && props.fieldId ? `${props.fieldId}-hint` : undefined\n)\n\nconst describedBy = computed(() => errorId.value ?? hintId.value)\n</script>\n\n<template>\n <div :class=\"['mint-form-field', layout === 'row' ? 'mint-form-field--row' : '']\">\n <div v-if=\"label\" class=\"mint-form-field__label-row\">\n <label\n :id=\"fieldId ? `${fieldId}-label` : undefined\"\n :for=\"htmlFor\"\n class=\"mint-form-field__label\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"mint-form-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <span\n v-if=\"!required && showOptional\"\n class=\"mint-form-field__optional\"\n >\n optional\n </span>\n </div>\n\n <div v-if=\"layout === 'row'\" class=\"mint-form-field__control\">\n <slot :described-by=\"describedBy\" />\n </div>\n <slot v-else :described-by=\"describedBy\" />\n\n <p v-if=\"error\" :id=\"errorId\" class=\"mint-form-field__error\" role=\"alert\">\n {{ error }}\n </p>\n <p v-else-if=\"hint\" :id=\"hintId\" class=\"mint-form-field__hint\">\n {{ hint }}\n </p>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Wraps a form control with a label, optional hint text, and validation error display. */\nimport { computed } from 'vue'\n\ninterface Props {\n label?: string\n error?: string\n hint?: string\n required?: boolean\n showOptional?: boolean\n htmlFor?: string\n /** Prefix for the label (`-label`), error and hint ids. */\n fieldId?: string\n /** `row` puts the label left and the control in a fixed 7.5rem column. Use for numbers, toggles, short enums. */\n layout?: 'stacked' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layout: 'stacked',\n})\n\nconst errorId = computed(() =>\n props.error && props.fieldId ? `${props.fieldId}-error` : undefined\n)\n\nconst hintId = computed(() =>\n !props.error && props.hint && props.fieldId ? `${props.fieldId}-hint` : undefined\n)\n\nconst describedBy = computed(() => errorId.value ?? hintId.value)\n</script>\n\n<template>\n <div :class=\"['mint-form-field', layout === 'row' ? 'mint-form-field--row' : '']\">\n <div v-if=\"label\" class=\"mint-form-field__label-row\">\n <label\n :id=\"fieldId ? `${fieldId}-label` : undefined\"\n :for=\"htmlFor\"\n class=\"mint-form-field__label\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"mint-form-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <span\n v-if=\"!required && showOptional\"\n class=\"mint-form-field__optional\"\n >\n optional\n </span>\n </div>\n\n <div v-if=\"layout === 'row'\" class=\"mint-form-field__control\">\n <slot :described-by=\"describedBy\" />\n </div>\n <slot v-else :described-by=\"describedBy\" />\n\n <p v-if=\"error\" :id=\"errorId\" class=\"mint-form-field__error\" role=\"alert\">\n {{ error }}\n </p>\n <p v-else-if=\"hint\" :id=\"hintId\" class=\"mint-form-field__hint\">\n {{ hint }}\n </p>\n </div>\n</template>\n","import { nextTick, ref, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseDropdownStateOptions {\n closeOnOutsideClick?: boolean\n closeOnEscape?: boolean\n /** Close the panel when the page scrolls or the viewport resizes. Default `false`. */\n closeOnScroll?: boolean\n insideRefs?: Array<Ref<HTMLElement | null>>\n /**\n * Element that counts as \"inside\" for outside-click closing, typically a\n * `useTemplateRef()`. Without one, bind the returned `rootRef` instead.\n */\n rootRef?: Ref<HTMLElement | null>\n /**\n * Element focus returns to when the panel closes with `close(true)` (Escape).\n * Pass one when the trigger lives outside `rootRef`; otherwise bind the\n * returned `triggerRef` to the trigger element.\n */\n triggerRef?: Ref<HTMLElement | null>\n onOpen?: () => void\n onClose?: () => void\n}\n\nexport interface UseDropdownStateReturn {\n isOpen: Ref<boolean>\n rootRef: Ref<HTMLElement | null>\n /** Bind to the trigger element so Escape can return focus to it. */\n triggerRef: Ref<HTMLElement | null>\n open: () => void\n /** Closes the panel; `returnFocus` moves focus back to `triggerRef`. */\n close: (returnFocus?: boolean) => void\n toggle: () => void\n handleClickOutside: (event: MouseEvent) => void\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * Shared disclosure state for dropdown-style SDK components: open/close state,\n * outside-click and Escape closing, optional scroll/resize closing, and focus\n * return to the trigger. `close(returnFocus)` mirrors `useMenuKeyboard`'s\n * contract, so the two compose directly.\n */\nexport function useDropdownState(options: UseDropdownStateOptions = {}): UseDropdownStateReturn {\n const isOpen = ref(false)\n const rootRef = options.rootRef ?? ref<HTMLElement | null>(null)\n const triggerRef = options.triggerRef ?? ref<HTMLElement | null>(null)\n const closeOnOutsideClick = options.closeOnOutsideClick ?? true\n const closeOnEscape = options.closeOnEscape ?? true\n const closeOnScroll = options.closeOnScroll ?? false\n\n function open(): void {\n if (isOpen.value) return\n isOpen.value = true\n options.onOpen?.()\n }\n\n function close(returnFocus = false): void {\n if (!isOpen.value) return\n isOpen.value = false\n options.onClose?.()\n if (returnFocus) {\n void nextTick(() => triggerRef.value?.focus())\n }\n }\n\n function toggle(): void {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n function handleClickOutside(event: MouseEvent): void {\n if (!closeOnOutsideClick || !isOpen.value || !rootRef.value) return\n const target = event.target\n if (\n target instanceof Node &&\n !rootRef.value.contains(target) &&\n !options.insideRefs?.some(ref => ref.value?.contains(target))\n ) {\n close()\n }\n }\n\n function handleKeydown(event: KeyboardEvent): void {\n if (closeOnEscape && event.key === 'Escape') {\n close(true)\n }\n }\n\n function handleViewportChange(): void {\n if (isOpen.value) close()\n }\n\n if (closeOnOutsideClick) {\n useEventListener(() => document, 'click', handleClickOutside)\n }\n if (closeOnEscape) {\n useEventListener(() => document, 'keydown', handleKeydown)\n }\n if (closeOnScroll) {\n useEventListener(() => window, 'scroll', handleViewportChange, true)\n useEventListener(() => window, 'resize', handleViewportChange)\n }\n\n return {\n isOpen,\n rootRef,\n triggerRef,\n open,\n close,\n toggle,\n handleClickOutside,\n handleKeydown,\n }\n}\n","import { nextTick } from 'vue'\n\nexport interface UseMenuKeyboardOptions {\n /** Returns the currently navigable items inside the open panel, in DOM order. */\n items: () => HTMLElement[]\n /** True while the panel is open. */\n isOpen: () => boolean\n /** Opens the panel. */\n open: () => void\n /** Closes the panel. When `returnFocus` is true, focus should return to the trigger. */\n close: (returnFocus?: boolean) => void\n}\n\nexport interface UseMenuKeyboardReturn {\n /**\n * Bind to the trigger's `@keydown`. ArrowDown/Enter/Space open the panel (when\n * closed) and focus its first item; ArrowUp opens it focused on the last item.\n */\n handleTriggerKeydown: (event: KeyboardEvent) => void\n /**\n * Bind to the open panel's `@keydown`. ArrowUp/ArrowDown cycle focus with\n * wraparound, Home/End jump to the first/last item, Escape closes, returns\n * focus to the trigger and stops propagating, and Tab closes without moving focus.\n */\n handlePanelKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * Shared keyboard contract for menu- and listbox-style disclosure panels (the\n * WAI-ARIA menu button pattern). Used by ActionMenu and the platform account menu,\n * each pairing it with `useDropdownState` for the disclosure state itself.\n */\nexport function useMenuKeyboard(options: UseMenuKeyboardOptions): UseMenuKeyboardReturn {\n function focusItem(position: 'first' | 'last') {\n void nextTick(() => {\n const items = options.items()\n const target = position === 'first' ? items[0] : items[items.length - 1]\n target?.focus()\n })\n }\n\n function handleTriggerKeydown(event: KeyboardEvent) {\n if (options.isOpen()) return\n\n if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n options.open()\n focusItem('first')\n return\n }\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n options.open()\n focusItem('last')\n }\n }\n\n function handlePanelKeydown(event: KeyboardEvent) {\n const items = options.items()\n const currentIndex = items.indexOf(document.activeElement as HTMLElement)\n\n if (event.key === 'Escape') {\n event.preventDefault()\n // The menu handles this Escape; an enclosing BaseModal must not close too.\n event.stopPropagation()\n options.close(true)\n return\n }\n if (event.key === 'Tab') {\n options.close()\n return\n }\n if (event.key === 'Home') {\n event.preventDefault()\n items[0]?.focus()\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n items[items.length - 1]?.focus()\n return\n }\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n\n event.preventDefault()\n const direction = event.key === 'ArrowDown' ? 1 : -1\n const nextIndex = (Math.max(currentIndex, 0) + direction + items.length) % items.length\n items[nextIndex]?.focus()\n }\n\n return { handleTriggerKeydown, handlePanelKeydown }\n}\n","<script setup lang=\"ts\">\n/** Drag-and-drop file upload zone with type filtering, size validation, and folder mode. */\nimport { ref, computed, watch } from 'vue'\n\ninterface Props {\n accept?: string\n multiple?: boolean\n maxSize?: number\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n mode?: 'file' | 'folder' | 'file+folder'\n /** Hide the selection list when a parent presents the files itself. */\n showFiles?: boolean\n /** Restore selections owned by a parent form; omitted for internal selection state. */\n files?: File[]\n rootName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n multiple: false,\n disabled: false,\n size: 'md',\n mode: 'file',\n showFiles: true,\n})\n\nconst emit = defineEmits<{\n upload: [files: File[], rootName?: string, relativePaths?: string[]]\n remove: [files: File[]]\n error: [message: string]\n}>()\n\nconst isDragOver = ref(false)\nconst inputRef = ref<HTMLInputElement>()\nconst selectedFiles = ref<File[]>([])\nconst folderName = ref<string | null>(null)\n\nwatch(() => [props.files, props.rootName] as const, ([files, rootName]) => {\n if (files === undefined) return\n selectedFiles.value = [...files]\n folderName.value = rootName ?? extractFolderName(files)\n}, { immediate: true })\n\nconst isFolder = computed(() => props.mode === 'folder')\nconst isMixed = computed(() => props.mode === 'file+folder')\n\nconst acceptLabel = computed(() => {\n if (!props.accept) return isFolder.value ? 'a folder' : 'any file'\n return props.accept.split(',').map(a => a.trim().replace('.', '').toUpperCase()).join(', ')\n})\n\nconst maxSizeLabel = computed(() => {\n if (!props.maxSize) return null\n if (props.maxSize >= 1024 * 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024 * 1024)).toFixed(1)} GB`\n }\n if (props.maxSize >= 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024)).toFixed(1)} MB`\n }\n if (props.maxSize >= 1024) {\n return `${(props.maxSize / 1024).toFixed(1)} KB`\n }\n return `${props.maxSize} bytes`\n})\n\nconst fileTypeMap: Record<string, { color: string; label: string }> = {\n csv: { color: '#10B981', label: 'CSV' },\n tsv: { color: '#10B981', label: 'TSV' },\n xlsx: { color: '#10B981', label: 'XLSX' },\n xls: { color: '#10B981', label: 'XLS' },\n pdf: { color: '#EF4444', label: 'PDF' },\n png: { color: '#8B5CF6', label: 'PNG' },\n jpg: { color: '#8B5CF6', label: 'JPG' },\n jpeg: { color: '#8B5CF6', label: 'JPEG' },\n gif: { color: '#8B5CF6', label: 'GIF' },\n svg: { color: '#8B5CF6', label: 'SVG' },\n webp: { color: '#8B5CF6', label: 'WEBP' },\n json: { color: '#F59E0B', label: 'JSON' },\n xml: { color: '#F59E0B', label: 'XML' },\n txt: { color: '#64748B', label: 'TXT' },\n zip: { color: '#6366F1', label: 'ZIP' },\n gz: { color: '#6366F1', label: 'GZ' },\n py: { color: '#3B82F6', label: 'PY' },\n js: { color: '#EAB308', label: 'JS' },\n ts: { color: '#3B82F6', label: 'TS' },\n fasta: { color: '#EC4899', label: 'FASTA' },\n fastq: { color: '#EC4899', label: 'FASTQ' },\n bam: { color: '#EC4899', label: 'BAM' },\n vcf: { color: '#EC4899', label: 'VCF' },\n}\n\nfunction getFileType(filename: string): { color: string; label: string } {\n const ext = filename.split('.').pop()?.toLowerCase() || ''\n return fileTypeMap[ext] || { color: '#94A3B8', label: ext.toUpperCase() || 'FILE' }\n}\n\nfunction validateFiles(files: FileList | File[]): File[] {\n const validFiles: File[] = []\n\n for (const file of Array.from(files)) {\n if (props.maxSize && file.size > props.maxSize) {\n emit('error', `File \"${file.name}\" exceeds maximum size of ${maxSizeLabel.value}`)\n continue\n }\n\n if (props.accept) {\n const acceptedTypes = props.accept.split(',').map(t => t.trim().toLowerCase())\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase()\n const fileType = file.type.toLowerCase()\n\n const isAccepted = acceptedTypes.some(type => {\n if (type.startsWith('.')) {\n return fileExt === type\n }\n if (type.endsWith('/*')) {\n return fileType.startsWith(type.replace('/*', '/'))\n }\n return fileType === type\n })\n\n if (!isAccepted) {\n emit('error', `File \"${file.name}\" is not an accepted file type`)\n continue\n }\n }\n\n validFiles.push(file)\n }\n\n return validFiles\n}\n\nfunction handleFiles(\n files: FileList | File[],\n folder?: string,\n explicitRelativePaths?: string[],\n) {\n const candidates = Array.from(files)\n const validFiles = validateFiles(files)\n if (validFiles.length === 0) return\n const relativePaths = validFiles.map((file) => {\n const candidateIndex = candidates.indexOf(file)\n return explicitRelativePaths?.[candidateIndex]\n || file.webkitRelativePath\n || (folder ? `${folder}/${file.name}` : file.name)\n })\n\n if (isFolder.value) {\n folderName.value = folder || extractFolderName(validFiles)\n selectedFiles.value = validFiles\n emit('upload', validFiles, folderName.value ?? undefined, relativePaths)\n } else if (!props.multiple) {\n selectedFiles.value = [validFiles[0]]\n emit('upload', [validFiles[0]], undefined, [relativePaths[0]])\n } else {\n selectedFiles.value = [...selectedFiles.value, ...validFiles]\n emit('upload', validFiles, undefined, relativePaths)\n }\n}\n\nfunction extractFolderName(files: File[]): string | null {\n if (files.length === 0) return null\n const firstPath = files[0].webkitRelativePath\n if (firstPath) {\n return firstPath.split('/')[0]\n }\n return null\n}\n\nasync function handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragOver.value = false\n if (props.disabled) return\n\n try {\n if (props.mode !== 'file' && event.dataTransfer?.items?.length) {\n await handleFolderDrop(event.dataTransfer.items)\n } else if (event.dataTransfer?.files) {\n handleFiles(event.dataTransfer.files)\n }\n } catch (cause) {\n emit('error', cause instanceof Error ? cause.message : 'Could not read the dropped folder.')\n }\n}\n\nasync function handleFolderDrop(items: DataTransferItemList) {\n const files: File[] = []\n const relativePaths: string[] = []\n let folderNameFromDrop: string | undefined\n\n // Capture live drag data before awaiting: the browser protects it after the drop handler.\n const dropped = Array.from(items, (item) => {\n const entry = item.webkitGetAsEntry?.()\n return { entry, file: entry ? null : item.getAsFile?.() }\n })\n for (const { entry, file: droppedFile } of dropped) {\n if (entry?.isDirectory) {\n folderNameFromDrop = entry.name\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n entry.name,\n )\n } else {\n const file = entry?.isFile\n ? await getFile(entry as FileSystemFileEntry)\n : droppedFile\n if (file) {\n files.push(file)\n relativePaths.push(file.name)\n }\n }\n }\n\n if (files.length > 0) {\n handleFiles(files, folderNameFromDrop, relativePaths)\n }\n}\n\nasync function readDirectory(\n directory: FileSystemDirectoryEntry,\n files: File[],\n relativePaths: string[],\n prefix: string,\n): Promise<void> {\n const reader = directory.createReader()\n // readEntries returns at most 100 entries per call per spec — must loop\n let batch: FileSystemEntry[]\n do {\n batch = await new Promise<FileSystemEntry[]>((resolve, reject) => {\n reader.readEntries(resolve, reject)\n })\n for (const entry of batch) {\n if (entry.isFile) {\n const file = await getFile(entry as FileSystemFileEntry)\n if (file) {\n files.push(file)\n relativePaths.push(`${prefix}/${file.name}`)\n }\n } else if (entry.isDirectory) {\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n `${prefix}/${entry.name}`,\n )\n }\n }\n } while (batch.length > 0)\n}\n\nfunction getFile(entry: FileSystemFileEntry): Promise<File | null> {\n return new Promise((resolve) => {\n entry.file(resolve, () => resolve(null))\n })\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n if (!props.disabled) {\n isDragOver.value = true\n }\n}\n\nfunction handleDragLeave() {\n isDragOver.value = false\n}\n\nfunction handleInputChange(event: Event) {\n const target = event.target as HTMLInputElement\n if (target.files) {\n handleFiles(target.files)\n }\n target.value = ''\n}\n\nfunction openFilePicker() {\n if (!props.disabled) {\n inputRef.value?.click()\n }\n}\n\nfunction removeFile(index: number) {\n const removed = selectedFiles.value[index]\n selectedFiles.value = selectedFiles.value.filter((_, i) => i !== index)\n if (isFolder.value && selectedFiles.value.length === 0) {\n folderName.value = null\n }\n if (removed) emit('remove', [removed])\n}\n\nfunction clearAll() {\n const removed = [...selectedFiles.value]\n selectedFiles.value = []\n folderName.value = null\n if (removed.length) emit('remove', removed)\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${bytes} bytes`\n}\n</script>\n\n<template>\n <div class=\"mint-file-uploader\">\n <!-- Dropzone -->\n <div\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"disabled\n ? 'File upload disabled'\n : isMixed\n ? 'Drop files or a folder, or click to choose files'\n : isFolder ? 'Click or drag a folder to upload' : 'Click or drag files to upload'\"\n :aria-disabled=\"disabled\"\n :class=\"[\n 'mint-file-uploader__dropzone',\n `mint-file-uploader__dropzone--${size}`,\n isDragOver ? 'mint-file-uploader__dropzone--dragover' : '',\n disabled ? 'mint-file-uploader__dropzone--disabled' : '',\n selectedFiles.length > 0 ? 'mint-file-uploader__dropzone--has-files' : '',\n ]\"\n @click=\"openFilePicker\"\n @keydown.enter=\"openFilePicker\"\n @keydown.space.prevent=\"openFilePicker\"\n @drop=\"handleDrop\"\n @dragover=\"handleDragOver\"\n @dragleave=\"handleDragLeave\"\n >\n <input\n ref=\"inputRef\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"isFolder || multiple\"\n :disabled=\"disabled\"\n :webkitdirectory=\"isFolder || undefined\"\n class=\"mint-file-uploader__input\"\n @change=\"handleInputChange\"\n />\n\n <div class=\"mint-file-uploader__content\">\n <svg\n v-if=\"isFolder\"\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n <svg\n v-else\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3\" /><path d=\"m16 16-4-4-4 4\" /><path d=\"M12 12v9\" />\n </svg>\n\n <p class=\"mint-file-uploader__text\">\n {{ isMixed ? 'Drop files or a folder, or click to choose files' : `Drop ${acceptLabel} or click` }}\n </p>\n </div>\n </div>\n\n <!-- Actions slot (e.g. template buttons) -->\n <div v-if=\"$slots.actions\" class=\"mint-file-uploader__actions\">\n <slot name=\"actions\" />\n </div>\n\n <!-- Folder summary display -->\n <div v-if=\"showFiles && isFolder && folderName && selectedFiles.length > 0\" class=\"mint-file-uploader__folder-summary\">\n <div class=\"mint-file-uploader__folder-info\">\n <div class=\"mint-file-uploader__folder-icon-wrapper\">\n <svg class=\"mint-file-uploader__folder-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n </div>\n <div class=\"mint-file-uploader__folder-details\">\n <span class=\"mint-file-uploader__folder-name\">{{ folderName }}</span>\n <span class=\"mint-file-uploader__folder-count\">{{ selectedFiles.length }} file{{ selectedFiles.length !== 1 ? 's' : '' }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear folder\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"clearAll\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- File list display -->\n <TransitionGroup\n v-if=\"showFiles && !isFolder && selectedFiles.length > 0\"\n tag=\"ul\"\n name=\"mint-file-uploader-item\"\n class=\"mint-file-uploader__list\"\n >\n <li\n v-for=\"(file, index) in selectedFiles\"\n :key=\"`${file.name}-${file.size}-${index}`\"\n class=\"mint-file-uploader__file\"\n >\n <div class=\"mint-file-uploader__file-info\">\n <span\n class=\"mint-file-uploader__file-badge\"\n :style=\"{ '--badge-color': getFileType(file.name).color }\"\n >\n {{ getFileType(file.name).label }}\n </span>\n <div class=\"mint-file-uploader__file-meta\">\n <span class=\"mint-file-uploader__file-name\">{{ file.name }}</span>\n <span class=\"mint-file-uploader__file-size\">{{ formatFileSize(file.size) }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n :aria-label=\"`Remove ${file.name}`\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"removeFile(index)\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </li>\n </TransitionGroup>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Drag-and-drop file upload zone with type filtering, size validation, and folder mode. */\nimport { ref, computed, watch } from 'vue'\n\ninterface Props {\n accept?: string\n multiple?: boolean\n maxSize?: number\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n mode?: 'file' | 'folder' | 'file+folder'\n /** Hide the selection list when a parent presents the files itself. */\n showFiles?: boolean\n /** Restore selections owned by a parent form; omitted for internal selection state. */\n files?: File[]\n rootName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n multiple: false,\n disabled: false,\n size: 'md',\n mode: 'file',\n showFiles: true,\n})\n\nconst emit = defineEmits<{\n upload: [files: File[], rootName?: string, relativePaths?: string[]]\n remove: [files: File[]]\n error: [message: string]\n}>()\n\nconst isDragOver = ref(false)\nconst inputRef = ref<HTMLInputElement>()\nconst selectedFiles = ref<File[]>([])\nconst folderName = ref<string | null>(null)\n\nwatch(() => [props.files, props.rootName] as const, ([files, rootName]) => {\n if (files === undefined) return\n selectedFiles.value = [...files]\n folderName.value = rootName ?? extractFolderName(files)\n}, { immediate: true })\n\nconst isFolder = computed(() => props.mode === 'folder')\nconst isMixed = computed(() => props.mode === 'file+folder')\n\nconst acceptLabel = computed(() => {\n if (!props.accept) return isFolder.value ? 'a folder' : 'any file'\n return props.accept.split(',').map(a => a.trim().replace('.', '').toUpperCase()).join(', ')\n})\n\nconst maxSizeLabel = computed(() => {\n if (!props.maxSize) return null\n if (props.maxSize >= 1024 * 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024 * 1024)).toFixed(1)} GB`\n }\n if (props.maxSize >= 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024)).toFixed(1)} MB`\n }\n if (props.maxSize >= 1024) {\n return `${(props.maxSize / 1024).toFixed(1)} KB`\n }\n return `${props.maxSize} bytes`\n})\n\nconst fileTypeMap: Record<string, { color: string; label: string }> = {\n csv: { color: '#10B981', label: 'CSV' },\n tsv: { color: '#10B981', label: 'TSV' },\n xlsx: { color: '#10B981', label: 'XLSX' },\n xls: { color: '#10B981', label: 'XLS' },\n pdf: { color: '#EF4444', label: 'PDF' },\n png: { color: '#8B5CF6', label: 'PNG' },\n jpg: { color: '#8B5CF6', label: 'JPG' },\n jpeg: { color: '#8B5CF6', label: 'JPEG' },\n gif: { color: '#8B5CF6', label: 'GIF' },\n svg: { color: '#8B5CF6', label: 'SVG' },\n webp: { color: '#8B5CF6', label: 'WEBP' },\n json: { color: '#F59E0B', label: 'JSON' },\n xml: { color: '#F59E0B', label: 'XML' },\n txt: { color: '#64748B', label: 'TXT' },\n zip: { color: '#6366F1', label: 'ZIP' },\n gz: { color: '#6366F1', label: 'GZ' },\n py: { color: '#3B82F6', label: 'PY' },\n js: { color: '#EAB308', label: 'JS' },\n ts: { color: '#3B82F6', label: 'TS' },\n fasta: { color: '#EC4899', label: 'FASTA' },\n fastq: { color: '#EC4899', label: 'FASTQ' },\n bam: { color: '#EC4899', label: 'BAM' },\n vcf: { color: '#EC4899', label: 'VCF' },\n}\n\nfunction getFileType(filename: string): { color: string; label: string } {\n const ext = filename.split('.').pop()?.toLowerCase() || ''\n return fileTypeMap[ext] || { color: '#94A3B8', label: ext.toUpperCase() || 'FILE' }\n}\n\nfunction validateFiles(files: FileList | File[]): File[] {\n const validFiles: File[] = []\n\n for (const file of Array.from(files)) {\n if (props.maxSize && file.size > props.maxSize) {\n emit('error', `File \"${file.name}\" exceeds maximum size of ${maxSizeLabel.value}`)\n continue\n }\n\n if (props.accept) {\n const acceptedTypes = props.accept.split(',').map(t => t.trim().toLowerCase())\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase()\n const fileType = file.type.toLowerCase()\n\n const isAccepted = acceptedTypes.some(type => {\n if (type.startsWith('.')) {\n return fileExt === type\n }\n if (type.endsWith('/*')) {\n return fileType.startsWith(type.replace('/*', '/'))\n }\n return fileType === type\n })\n\n if (!isAccepted) {\n emit('error', `File \"${file.name}\" is not an accepted file type`)\n continue\n }\n }\n\n validFiles.push(file)\n }\n\n return validFiles\n}\n\nfunction handleFiles(\n files: FileList | File[],\n folder?: string,\n explicitRelativePaths?: string[],\n) {\n const candidates = Array.from(files)\n const validFiles = validateFiles(files)\n if (validFiles.length === 0) return\n const relativePaths = validFiles.map((file) => {\n const candidateIndex = candidates.indexOf(file)\n return explicitRelativePaths?.[candidateIndex]\n || file.webkitRelativePath\n || (folder ? `${folder}/${file.name}` : file.name)\n })\n\n if (isFolder.value) {\n folderName.value = folder || extractFolderName(validFiles)\n selectedFiles.value = validFiles\n emit('upload', validFiles, folderName.value ?? undefined, relativePaths)\n } else if (!props.multiple) {\n selectedFiles.value = [validFiles[0]]\n emit('upload', [validFiles[0]], undefined, [relativePaths[0]])\n } else {\n selectedFiles.value = [...selectedFiles.value, ...validFiles]\n emit('upload', validFiles, undefined, relativePaths)\n }\n}\n\nfunction extractFolderName(files: File[]): string | null {\n if (files.length === 0) return null\n const firstPath = files[0].webkitRelativePath\n if (firstPath) {\n return firstPath.split('/')[0]\n }\n return null\n}\n\nasync function handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragOver.value = false\n if (props.disabled) return\n\n try {\n if (props.mode !== 'file' && event.dataTransfer?.items?.length) {\n await handleFolderDrop(event.dataTransfer.items)\n } else if (event.dataTransfer?.files) {\n handleFiles(event.dataTransfer.files)\n }\n } catch (cause) {\n emit('error', cause instanceof Error ? cause.message : 'Could not read the dropped folder.')\n }\n}\n\nasync function handleFolderDrop(items: DataTransferItemList) {\n const files: File[] = []\n const relativePaths: string[] = []\n let folderNameFromDrop: string | undefined\n\n // Capture live drag data before awaiting: the browser protects it after the drop handler.\n const dropped = Array.from(items, (item) => {\n const entry = item.webkitGetAsEntry?.()\n return { entry, file: entry ? null : item.getAsFile?.() }\n })\n for (const { entry, file: droppedFile } of dropped) {\n if (entry?.isDirectory) {\n folderNameFromDrop = entry.name\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n entry.name,\n )\n } else {\n const file = entry?.isFile\n ? await getFile(entry as FileSystemFileEntry)\n : droppedFile\n if (file) {\n files.push(file)\n relativePaths.push(file.name)\n }\n }\n }\n\n if (files.length > 0) {\n handleFiles(files, folderNameFromDrop, relativePaths)\n }\n}\n\nasync function readDirectory(\n directory: FileSystemDirectoryEntry,\n files: File[],\n relativePaths: string[],\n prefix: string,\n): Promise<void> {\n const reader = directory.createReader()\n // readEntries returns at most 100 entries per call per spec — must loop\n let batch: FileSystemEntry[]\n do {\n batch = await new Promise<FileSystemEntry[]>((resolve, reject) => {\n reader.readEntries(resolve, reject)\n })\n for (const entry of batch) {\n if (entry.isFile) {\n const file = await getFile(entry as FileSystemFileEntry)\n if (file) {\n files.push(file)\n relativePaths.push(`${prefix}/${file.name}`)\n }\n } else if (entry.isDirectory) {\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n `${prefix}/${entry.name}`,\n )\n }\n }\n } while (batch.length > 0)\n}\n\nfunction getFile(entry: FileSystemFileEntry): Promise<File | null> {\n return new Promise((resolve) => {\n entry.file(resolve, () => resolve(null))\n })\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n if (!props.disabled) {\n isDragOver.value = true\n }\n}\n\nfunction handleDragLeave() {\n isDragOver.value = false\n}\n\nfunction handleInputChange(event: Event) {\n const target = event.target as HTMLInputElement\n if (target.files) {\n handleFiles(target.files)\n }\n target.value = ''\n}\n\nfunction openFilePicker() {\n if (!props.disabled) {\n inputRef.value?.click()\n }\n}\n\nfunction removeFile(index: number) {\n const removed = selectedFiles.value[index]\n selectedFiles.value = selectedFiles.value.filter((_, i) => i !== index)\n if (isFolder.value && selectedFiles.value.length === 0) {\n folderName.value = null\n }\n if (removed) emit('remove', [removed])\n}\n\nfunction clearAll() {\n const removed = [...selectedFiles.value]\n selectedFiles.value = []\n folderName.value = null\n if (removed.length) emit('remove', removed)\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${bytes} bytes`\n}\n</script>\n\n<template>\n <div class=\"mint-file-uploader\">\n <!-- Dropzone -->\n <div\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"disabled\n ? 'File upload disabled'\n : isMixed\n ? 'Drop files or a folder, or click to choose files'\n : isFolder ? 'Click or drag a folder to upload' : 'Click or drag files to upload'\"\n :aria-disabled=\"disabled\"\n :class=\"[\n 'mint-file-uploader__dropzone',\n `mint-file-uploader__dropzone--${size}`,\n isDragOver ? 'mint-file-uploader__dropzone--dragover' : '',\n disabled ? 'mint-file-uploader__dropzone--disabled' : '',\n selectedFiles.length > 0 ? 'mint-file-uploader__dropzone--has-files' : '',\n ]\"\n @click=\"openFilePicker\"\n @keydown.enter=\"openFilePicker\"\n @keydown.space.prevent=\"openFilePicker\"\n @drop=\"handleDrop\"\n @dragover=\"handleDragOver\"\n @dragleave=\"handleDragLeave\"\n >\n <input\n ref=\"inputRef\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"isFolder || multiple\"\n :disabled=\"disabled\"\n :webkitdirectory=\"isFolder || undefined\"\n class=\"mint-file-uploader__input\"\n @change=\"handleInputChange\"\n />\n\n <div class=\"mint-file-uploader__content\">\n <svg\n v-if=\"isFolder\"\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n <svg\n v-else\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3\" /><path d=\"m16 16-4-4-4 4\" /><path d=\"M12 12v9\" />\n </svg>\n\n <p class=\"mint-file-uploader__text\">\n {{ isMixed ? 'Drop files or a folder, or click to choose files' : `Drop ${acceptLabel} or click` }}\n </p>\n </div>\n </div>\n\n <!-- Actions slot (e.g. template buttons) -->\n <div v-if=\"$slots.actions\" class=\"mint-file-uploader__actions\">\n <slot name=\"actions\" />\n </div>\n\n <!-- Folder summary display -->\n <div v-if=\"showFiles && isFolder && folderName && selectedFiles.length > 0\" class=\"mint-file-uploader__folder-summary\">\n <div class=\"mint-file-uploader__folder-info\">\n <div class=\"mint-file-uploader__folder-icon-wrapper\">\n <svg class=\"mint-file-uploader__folder-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n </div>\n <div class=\"mint-file-uploader__folder-details\">\n <span class=\"mint-file-uploader__folder-name\">{{ folderName }}</span>\n <span class=\"mint-file-uploader__folder-count\">{{ selectedFiles.length }} file{{ selectedFiles.length !== 1 ? 's' : '' }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear folder\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"clearAll\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- File list display -->\n <TransitionGroup\n v-if=\"showFiles && !isFolder && selectedFiles.length > 0\"\n tag=\"ul\"\n name=\"mint-file-uploader-item\"\n class=\"mint-file-uploader__list\"\n >\n <li\n v-for=\"(file, index) in selectedFiles\"\n :key=\"`${file.name}-${file.size}-${index}`\"\n class=\"mint-file-uploader__file\"\n >\n <div class=\"mint-file-uploader__file-info\">\n <span\n class=\"mint-file-uploader__file-badge\"\n :style=\"{ '--badge-color': getFileType(file.name).color }\"\n >\n {{ getFileType(file.name).label }}\n </span>\n <div class=\"mint-file-uploader__file-meta\">\n <span class=\"mint-file-uploader__file-name\">{{ file.name }}</span>\n <span class=\"mint-file-uploader__file-size\">{{ formatFileSize(file.size) }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n :aria-label=\"`Remove ${file.name}`\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"removeFile(index)\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </li>\n </TransitionGroup>\n </div>\n</template>\n","import type { DatePreset, SelectOption } from '../types'\n\ninterface ExperimentCodeSource {\n id?: number | null\n experiment_code?: string | null\n}\n\nexport function formatExperimentDate(dateStr: string): string {\n try {\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n } catch {\n return dateStr\n }\n}\n\nexport function datePresetToISO(preset: DatePreset): string {\n const now = new Date()\n const days = preset === 'last_7_days' ? 7 : preset === 'last_30_days' ? 30 : 90\n const d = new Date(now.getTime() - days * 86_400_000)\n return d.toISOString()\n}\n\nexport function resolveExperimentCode(experiment: ExperimentCodeSource): string | undefined {\n if (experiment.experiment_code) return experiment.experiment_code\n return undefined\n}\n\n// Mirrors vue-router's LocationQuery, whose array members are `string | null`.\n// Declaring `string[]` here made the helper reject the very type every caller\n// passes it, so keep this assignable from LocationQuery without importing\n// vue-router (the SDK does not depend on it).\ntype RouteQueryValue = string | null | undefined | readonly (string | null | undefined)[]\ntype RouteQueryLike = Record<string, RouteQueryValue>\n\n/**\n * Reads the experiment id a deep link was opened with.\n *\n * Returns an id and never a label: a display name belongs to the platform, so\n * callers must resolve it (see `useExperimentStore().selectById`) rather than\n * derive one from the query or the id itself.\n */\nexport function experimentIdFromRoute(query: RouteQueryLike): number | null {\n const raw = query.experiment_id ?? query.experimentId\n const value = Array.isArray(raw) ? raw.find(item => typeof item === 'string') : raw\n if (typeof value !== 'string' || !value) return null\n const id = Number(value)\n return Number.isInteger(id) && id > 0 ? id : null\n}\n\nexport const DATE_PRESET_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'Any time' },\n { value: 'last_7_days', label: 'Last 7 days' },\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_90_days', label: 'Last 90 days' },\n]\n\nexport const SORT_OPTIONS: SelectOption<string>[] = [\n { value: 'created_at:desc', label: 'Newest first' },\n { value: 'created_at:asc', label: 'Oldest first' },\n { value: 'updated_at:desc', label: 'Recently updated' },\n { value: 'name:asc', label: 'Name A\\u2013Z' },\n { value: 'name:desc', label: 'Name Z\\u2013A' },\n]\n","import {\n ref,\n computed,\n provide,\n toValue,\n watch,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\nimport { useExperimentStore } from '../stores/experiment'\nimport { resolveExperimentCode } from './experiment-utils'\n\nexport interface UseAppExperimentOptions {\n /**\n * Called when the shared store adopts an experiment — a modal selection or a\n * resolved deep link. The record always comes from the platform.\n */\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n}\n\nexport interface AppExperimentPopoverBinding {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: ExperimentStatus\n /** An experiment is bound but its record has not arrived yet. */\n isResolving: boolean\n /** Resolution failed; the binding is kept so the user can retry or detach. */\n error?: string\n showSave: boolean\n showDetach: boolean\n saveDisabled: boolean\n saveDisabledMessage?: string\n saveLoading: boolean\n saveSuccessMessage?: string\n}\n\nexport interface AppExperimentSelectorModalBinding {\n open: boolean\n currentExperimentId: number | null\n}\n\nexport interface UseAppExperimentReturn {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n closeModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport interface AppExperimentState {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\n/**\n * Projects the current experiment from the shared store into an AppTopBar app\n * shell, and owns the shell-local concerns the store has no opinion on: the\n * selector modal's open state and the save flow.\n *\n * The composable never writes a selection of its own. `ExperimentSelectorModal`\n * commits to the store and this reads back, so a displayed name can only ever\n * have come from the platform.\n *\n * @example Recommended\n * ```ts\n * const appExperiment = useAppExperiment({\n * onSelect: experiment => loadExperiment(experiment.id),\n * })\n * ```\n */\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const store = useExperimentStore()\n\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const experimentName = computed(() => store.current?.name)\n const experimentCode = computed(() =>\n store.current ? resolveExperimentCode(store.current) : undefined,\n )\n const experimentStatus = computed(() => store.current?.status)\n // Set while resolving and after a failed resolve, so the shell can tell\n // \"nothing selected\" apart from \"selected but not resolved\".\n const experimentId = computed(() => store.currentId)\n const isResolving = computed(() => store.isResolving)\n const error = computed(() => store.error)\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n const popover = computed<AppExperimentPopoverBinding>(() => ({\n experimentName: experimentName.value,\n experimentCode: experimentCode.value,\n experimentStatus: experimentStatus.value,\n isResolving: isResolving.value,\n error: error.value ?? undefined,\n showSave: showSave.value,\n showDetach: showDetach.value,\n saveDisabled: saveDisabled.value,\n saveDisabledMessage: saveDisabledMessage.value,\n saveLoading: saveLoading.value,\n saveSuccessMessage: saveSuccessMessage.value,\n }))\n const selectorModal = computed<AppExperimentSelectorModalBinding>(() => ({\n open: showModal.value,\n currentExperimentId: experimentId.value,\n }))\n\n if (options.onSelect) {\n // Keyed by id, so a refresh of the same experiment is not a new selection.\n watch(\n () => store.current?.id,\n (id) => {\n if (id !== undefined && store.current) void options.onSelect?.(store.current)\n },\n )\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n store.clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n}\n","/**\n * Stable references for plugin secret settings.\n *\n * A settings response never carries a secret's value. Every secret leaf is a\n * marker instead:\n *\n * - `{ \"$secret\": \"sec_…\", \"set\": true }` — a stored secret, referenced by a\n * stable opaque id. Send the marker back unchanged to keep the stored value.\n * - `null` — nothing stored at that position.\n * - `{ \"$secret\": null, \"locked\": true }` — the effective value comes from the\n * environment and is never written back.\n *\n * On save each secret leaf accepts the reference, a plain string (a new value),\n * or `null` (clear). Payloads carry `secret_format: \"ref\"` so a `null` reads as\n * a deliberate clear rather than the deprecated \"unchanged\" placeholder.\n */\n\n/** Reserved marker key that references a stored secret. */\nexport const REF_KEY = '$secret'\n\n/** Reserved payload key declaring which secret wire format a client speaks. */\nexport const FORMAT_KEY = 'secret_format'\n\n/** Wire format published and understood by this SDK. */\nexport const FORMAT_REF = 'ref'\n\n/** One `$secret` marker as published by a settings response. */\nexport interface PluginSecretRef {\n $secret: string | null\n set?: boolean\n locked?: boolean\n}\n\n/** What a settings form should tell the user about one secret field. */\nexport type PluginSecretState = 'set' | 'unset' | 'environment'\n\nconst MARKER_KEYS = new Set([REF_KEY, 'set', 'locked'])\n\n/** Return whether one settings value is a `$secret` reference marker. */\nexport function isRef(value: unknown): value is PluginSecretRef {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n if (!(REF_KEY in record)) return false\n return Object.keys(record).every(key => MARKER_KEYS.has(key))\n}\n\n/** Return the stored secret id behind a marker, or `null` when nothing is stored. */\nexport function id(value: unknown): string | null {\n if (!isRef(value)) return null\n return typeof value.$secret === 'string' ? value.$secret : null\n}\n\n/** Classify one secret field for display: stored, unset, or environment-provided. */\nexport function state(value: unknown): PluginSecretState {\n if (isRef(value)) {\n if (value.locked) return 'environment'\n return typeof value.$secret === 'string' ? 'set' : 'unset'\n }\n return typeof value === 'string' && value.length > 0 ? 'set' : 'unset'\n}\n\n/** Human label for one secret field's state. */\nexport function label(value: unknown): string {\n const current = state(value)\n if (current === 'environment') return 'Provided by environment'\n return current === 'set' ? 'Set' : 'Not set'\n}\n\n/** Whether a secret field is read-only because the environment supplies it. */\nexport function isLocked(value: unknown): boolean {\n return isRef(value) && value.locked === true\n}\n\n/**\n * Value to submit for an untouched secret field: the reference, unchanged.\n *\n * A locked marker round-trips too, which is how the platform keeps a stored\n * value that an environment variable currently hides.\n */\nexport function keep(current: unknown): PluginSecretRef | null {\n if (isRef(current)) return { ...current }\n return null\n}\n\n/** Value to submit when the user typed a new secret. */\nexport function set(value: string): string {\n return value\n}\n\n/** Value to submit when the user cleared a secret. */\nexport function clear(): null {\n return null\n}\n\n/** Whether a settings response declares the `$secret` reference wire format. */\nexport function usesReferences(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false\n return (\n (response as Record<string, unknown>)[FORMAT_KEY]\n === FORMAT_REF\n )\n}\n","<script setup lang=\"ts\">\n/** Edits one plugin secret setting: shows set / not set / provided by environment, and submits a `$secret` reference, a new value, or `null`. */\nimport { computed, ref, watch } from 'vue'\nimport BaseInput from './BaseInput.vue'\nimport BaseButton from './BaseButton.vue'\nimport * as pluginSecret from '../utils/pluginSecrets'\nimport type { PluginSecretRef, PluginSecretState } from '../utils/pluginSecrets'\n\ntype SecretValue = PluginSecretRef | string | null\n\ninterface Props {\n /** The `$secret` marker from the settings response, a typed string, or `null`. */\n modelValue?: SecretValue\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** Label on the control that starts entering a replacement value. */\n changeLabel?: string\n /** Label on the control that clears a stored secret. */\n clearLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: null,\n placeholder: 'Enter a new value',\n disabled: false,\n invalid: false,\n size: 'md',\n changeLabel: 'Change',\n clearLabel: 'Clear',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: SecretValue]\n}>()\n\n/** The reference this field started from, so an abandoned edit can restore it. */\nconst storedReference = ref<PluginSecretRef | null>(pluginSecret.keep(props.modelValue))\nconst isEditing = ref(typeof props.modelValue === 'string')\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (pluginSecret.isRef(value)) {\n storedReference.value = pluginSecret.keep(value)\n isEditing.value = false\n }\n },\n)\n\nconst state = computed<PluginSecretState>(() => pluginSecret.state(props.modelValue))\nconst locked = computed(() => pluginSecret.isLocked(props.modelValue)\n || pluginSecret.isLocked(storedReference.value))\nconst statusLabel = computed(() => isEditing.value\n ? 'New value'\n : pluginSecret.label(props.modelValue))\nconst typedValue = computed(() => typeof props.modelValue === 'string' ? props.modelValue : '')\nconst canClear = computed(() => !locked.value && (state.value === 'set' || isEditing.value))\n\nfunction startEditing(): void {\n if (props.disabled || locked.value) return\n isEditing.value = true\n emit('update:modelValue', pluginSecret.set(''))\n}\n\nfunction updateTyped(value: string | number | null): void {\n emit('update:modelValue', pluginSecret.set(value == null ? '' : String(value)))\n}\n\nfunction cancelEditing(): void {\n isEditing.value = false\n emit('update:modelValue', storedReference.value ? { ...storedReference.value } : null)\n}\n\nfunction clear(): void {\n if (props.disabled || locked.value) return\n isEditing.value = false\n storedReference.value = null\n emit('update:modelValue', pluginSecret.clear())\n}\n</script>\n\n<template>\n <div class=\"mint-secret-input\" :class=\"{ 'mint-secret-input--error': invalid }\">\n <div class=\"mint-secret-input__status\">\n <span\n class=\"mint-secret-input__badge\"\n :class=\"`mint-secret-input__badge--${isEditing ? 'pending' : state}`\"\n ><span class=\"mint-secret-input__dot\" aria-hidden=\"true\" />{{ statusLabel }}</span>\n <span v-if=\"locked\" class=\"mint-secret-input__hint\">\n This value comes from the environment and cannot be edited here.\n </span>\n </div>\n\n <BaseInput\n v-if=\"isEditing\"\n type=\"password\"\n autocomplete=\"new-password\"\n :model-value=\"typedValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n @update:model-value=\"updateTyped\"\n />\n\n <div class=\"mint-secret-input__actions\">\n <BaseButton\n v-if=\"!isEditing\"\n type=\"button\"\n variant=\"secondary\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled || locked\"\n @click=\"startEditing\"\n >\n {{ changeLabel }}\n </BaseButton>\n <BaseButton\n v-else\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"cancelEditing\"\n >\n Cancel\n </BaseButton>\n <BaseButton\n v-if=\"canClear\"\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Edits one plugin secret setting: shows set / not set / provided by environment, and submits a `$secret` reference, a new value, or `null`. */\nimport { computed, ref, watch } from 'vue'\nimport BaseInput from './BaseInput.vue'\nimport BaseButton from './BaseButton.vue'\nimport * as pluginSecret from '../utils/pluginSecrets'\nimport type { PluginSecretRef, PluginSecretState } from '../utils/pluginSecrets'\n\ntype SecretValue = PluginSecretRef | string | null\n\ninterface Props {\n /** The `$secret` marker from the settings response, a typed string, or `null`. */\n modelValue?: SecretValue\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** Label on the control that starts entering a replacement value. */\n changeLabel?: string\n /** Label on the control that clears a stored secret. */\n clearLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: null,\n placeholder: 'Enter a new value',\n disabled: false,\n invalid: false,\n size: 'md',\n changeLabel: 'Change',\n clearLabel: 'Clear',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: SecretValue]\n}>()\n\n/** The reference this field started from, so an abandoned edit can restore it. */\nconst storedReference = ref<PluginSecretRef | null>(pluginSecret.keep(props.modelValue))\nconst isEditing = ref(typeof props.modelValue === 'string')\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (pluginSecret.isRef(value)) {\n storedReference.value = pluginSecret.keep(value)\n isEditing.value = false\n }\n },\n)\n\nconst state = computed<PluginSecretState>(() => pluginSecret.state(props.modelValue))\nconst locked = computed(() => pluginSecret.isLocked(props.modelValue)\n || pluginSecret.isLocked(storedReference.value))\nconst statusLabel = computed(() => isEditing.value\n ? 'New value'\n : pluginSecret.label(props.modelValue))\nconst typedValue = computed(() => typeof props.modelValue === 'string' ? props.modelValue : '')\nconst canClear = computed(() => !locked.value && (state.value === 'set' || isEditing.value))\n\nfunction startEditing(): void {\n if (props.disabled || locked.value) return\n isEditing.value = true\n emit('update:modelValue', pluginSecret.set(''))\n}\n\nfunction updateTyped(value: string | number | null): void {\n emit('update:modelValue', pluginSecret.set(value == null ? '' : String(value)))\n}\n\nfunction cancelEditing(): void {\n isEditing.value = false\n emit('update:modelValue', storedReference.value ? { ...storedReference.value } : null)\n}\n\nfunction clear(): void {\n if (props.disabled || locked.value) return\n isEditing.value = false\n storedReference.value = null\n emit('update:modelValue', pluginSecret.clear())\n}\n</script>\n\n<template>\n <div class=\"mint-secret-input\" :class=\"{ 'mint-secret-input--error': invalid }\">\n <div class=\"mint-secret-input__status\">\n <span\n class=\"mint-secret-input__badge\"\n :class=\"`mint-secret-input__badge--${isEditing ? 'pending' : state}`\"\n ><span class=\"mint-secret-input__dot\" aria-hidden=\"true\" />{{ statusLabel }}</span>\n <span v-if=\"locked\" class=\"mint-secret-input__hint\">\n This value comes from the environment and cannot be edited here.\n </span>\n </div>\n\n <BaseInput\n v-if=\"isEditing\"\n type=\"password\"\n autocomplete=\"new-password\"\n :model-value=\"typedValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n @update:model-value=\"updateTyped\"\n />\n\n <div class=\"mint-secret-input__actions\">\n <BaseButton\n v-if=\"!isEditing\"\n type=\"button\"\n variant=\"secondary\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled || locked\"\n @click=\"startEditing\"\n >\n {{ changeLabel }}\n </BaseButton>\n <BaseButton\n v-else\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"cancelEditing\"\n >\n Cancel\n </BaseButton>\n <BaseButton\n v-if=\"canClear\"\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Lets users type and add tags with autocomplete suggestions, categories, and a max-tag cap. */\nimport { ref, computed, useTemplateRef } from 'vue'\nimport { useSelectionLimit } from '../composables/useSelectionLimit'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport type { Tone } from '../types'\n\ninterface TagSuggestion {\n value: string\n count?: number\n}\n\ninterface TagCategory {\n name: string\n prefix: string\n tone?: Tone\n}\n\ninterface Props {\n modelValue?: string[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n maxTags?: number\n allowDuplicates?: boolean\n suggestions?: string[] | TagSuggestion[]\n categories?: TagCategory[]\n activeCategory?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n disabled: false,\n invalid: false,\n size: 'md',\n allowDuplicates: false,\n suggestions: () => [],\n categories: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n 'update:activeCategory': [prefix: string]\n}>()\n\nconst inputValue = ref('')\nconst highlightedIndex = ref(-1)\n// The text input doubles as the dropdown trigger, so focus restoration is the\n// composable's `triggerRef` rather than a component-local refocus helper.\nconst {\n isOpen: dropdownOpen,\n triggerRef: inputRef,\n open: openDropdown,\n close: closeDropdown,\n} = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('root'),\n onClose: () => {\n highlightedIndex.value = -1\n },\n})\n\nconst selectionLimit = useSelectionLimit({\n count: () => props.modelValue.length,\n max: () => props.maxTags,\n})\nconst canAddMore = selectionLimit.canAddMore\n\nconst normalizedSuggestions = computed<TagSuggestion[]>(() => {\n return props.suggestions.map(s => typeof s === 'string' ? { value: s } : s)\n})\n\nconst filteredSuggestions = computed<TagSuggestion[]>(() => {\n const q = inputValue.value.trim().toLowerCase()\n if (!q) return []\n return normalizedSuggestions.value\n .filter(s => s.value.toLowerCase().startsWith(q) && !props.modelValue.includes(s.value))\n .slice(0, 8)\n})\n\nfunction categoryFor(tag: string): TagCategory | undefined {\n const colonIdx = tag.indexOf(':')\n if (colonIdx === -1) return undefined\n const prefix = tag.slice(0, colonIdx)\n return props.categories.find(c => c.prefix === prefix)\n}\n\n// 3f: a category is shown by a group-color dot (3a palette), never a semantic tint.\nconst GROUP_COLORS = [\n 'var(--mint-sample-1)', 'var(--mint-sample-2)', 'var(--mint-sample-3)', 'var(--mint-sample-4)',\n 'var(--mint-sample-5)', 'var(--mint-sample-6)', 'var(--mint-sample-7)', 'var(--mint-sample-8)',\n]\n\nfunction groupColor(category: TagCategory): string {\n return GROUP_COLORS[props.categories.indexOf(category) % GROUP_COLORS.length]\n}\n\nfunction addTag(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return\n if (!selectionLimit.canAdd()) return\n\n // If a category is active and user didn't already type a prefix, prepend it\n let final = trimmed\n if (props.activeCategory && !trimmed.includes(':')) {\n final = `${props.activeCategory}:${trimmed}`\n }\n\n if (!props.allowDuplicates && props.modelValue.includes(final)) return\n\n emit('update:modelValue', [...props.modelValue, final])\n inputValue.value = ''\n closeDropdown()\n}\n\nfunction removeTag(index: number) {\n if (props.disabled) return\n const newTags = [...props.modelValue]\n newTags.splice(index, 1)\n emit('update:modelValue', newTags)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'ArrowDown' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.min(highlightedIndex.value + 1, filteredSuggestions.value.length - 1)\n openDropdown()\n return\n }\n if (event.key === 'ArrowUp' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)\n return\n }\n if (event.key === 'Enter' || event.key === ',') {\n event.preventDefault()\n if (highlightedIndex.value >= 0 && filteredSuggestions.value[highlightedIndex.value]) {\n addTag(filteredSuggestions.value[highlightedIndex.value].value)\n } else {\n addTag(inputValue.value)\n }\n return\n }\n if (event.key === 'Escape') {\n closeDropdown(true)\n return\n }\n if (event.key === 'Backspace' && !inputValue.value && props.modelValue.length > 0) {\n removeTag(props.modelValue.length - 1)\n }\n}\n\nfunction handleFocus() {\n if (filteredSuggestions.value.length) openDropdown()\n}\n\nfunction handleBlur() {\n // Delay so a click on a suggestion fires first\n setTimeout(() => {\n closeDropdown()\n }, 120)\n}\n\nfunction handlePaste(event: ClipboardEvent) {\n event.preventDefault()\n const text = event.clipboardData?.getData('text')\n if (!text) return\n\n const tags = text.split(/[,\\n]/).map(t => t.trim()).filter(Boolean)\n const newTags = [...props.modelValue]\n\n for (const tag of tags) {\n if (!selectionLimit.canAdd(1, newTags.length)) break\n if (!props.allowDuplicates && newTags.includes(tag)) continue\n newTags.push(tag)\n }\n\n emit('update:modelValue', newTags)\n}\n\nfunction focusInput() {\n inputRef.value?.focus()\n}\n\nfunction setCategory(prefix: string) {\n emit('update:activeCategory', prefix === props.activeCategory ? '' : prefix)\n}\n\nfunction onInputEvent() {\n if (filteredSuggestions.value.length > 0) {\n openDropdown()\n } else {\n closeDropdown()\n }\n highlightedIndex.value = -1\n}\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"[\n 'mint-tags-input',\n `mint-tags-input--${size}`,\n invalid ? 'mint-tags-input--error' : '',\n disabled ? 'mint-tags-input--disabled' : '',\n categories.length ? 'mint-tags-input--categorized' : '',\n ]\"\n >\n <!-- Category switcher (only if categories defined) -->\n <div v-if=\"categories.length\" class=\"mint-tags-input__categories\">\n <button\n v-for=\"cat in categories\"\n :key=\"cat.prefix\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__category',\n `mint-tags-input__category--${cat.tone ?? 'neutral'}`,\n activeCategory === cat.prefix ? 'mint-tags-input__category--active' : '',\n ]\"\n :disabled=\"disabled\"\n @click=\"setCategory(cat.prefix)\"\n >\n <span class=\"mint-tags-input__tag-dot\" :style=\"{ background: groupColor(cat) }\" aria-hidden=\"true\" />\n {{ cat.name }}\n </button>\n </div>\n\n <div class=\"mint-tags-input__field\" @click=\"focusInput\">\n <span\n v-for=\"(tag, index) in modelValue\"\n :key=\"`${tag}-${index}`\"\n :class=\"[\n 'mint-tags-input__tag',\n `mint-tags-input__tag--${size}`,\n categoryFor(tag) ? `mint-tags-input__tag--${categoryFor(tag)?.tone ?? 'neutral'}` : '',\n ]\"\n >\n <span\n v-if=\"categoryFor(tag)\"\n class=\"mint-tags-input__tag-dot\"\n :style=\"{ background: groupColor(categoryFor(tag)!) }\"\n aria-hidden=\"true\"\n />\n {{ tag }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n :aria-label=\"`Remove ${tag}`\"\n class=\"mint-tags-input__tag-remove\"\n @click.stop=\"removeTag(index)\"\n >\n <svg class=\"mint-tags-input__tag-remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n\n <input\n ref=\"inputRef\"\n v-model=\"inputValue\"\n type=\"text\"\n :placeholder=\"modelValue.length === 0 ? placeholder : ''\"\n :disabled=\"disabled || !canAddMore\"\n :class=\"['mint-tags-input__input', `mint-tags-input__input--${size}`]\"\n @keydown=\"handleKeydown\"\n @paste=\"handlePaste\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n @input=\"onInputEvent\"\n />\n\n <!-- Autocomplete dropdown -->\n <div\n v-if=\"dropdownOpen && filteredSuggestions.length\"\n class=\"mint-tags-input__dropdown\"\n >\n <button\n v-for=\"(sug, i) in filteredSuggestions\"\n :key=\"sug.value\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__dropdown-item',\n i === highlightedIndex ? 'mint-tags-input__dropdown-item--highlighted' : '',\n ]\"\n @mousedown.prevent=\"addTag(sug.value)\"\n >\n <span>{{ sug.value }}</span>\n <span v-if=\"sug.count !== undefined\" class=\"mint-tags-input__dropdown-count\">\n {{ sug.count }}\n </span>\n </button>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Lets users type and add tags with autocomplete suggestions, categories, and a max-tag cap. */\nimport { ref, computed, useTemplateRef } from 'vue'\nimport { useSelectionLimit } from '../composables/useSelectionLimit'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport type { Tone } from '../types'\n\ninterface TagSuggestion {\n value: string\n count?: number\n}\n\ninterface TagCategory {\n name: string\n prefix: string\n tone?: Tone\n}\n\ninterface Props {\n modelValue?: string[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n maxTags?: number\n allowDuplicates?: boolean\n suggestions?: string[] | TagSuggestion[]\n categories?: TagCategory[]\n activeCategory?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n disabled: false,\n invalid: false,\n size: 'md',\n allowDuplicates: false,\n suggestions: () => [],\n categories: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n 'update:activeCategory': [prefix: string]\n}>()\n\nconst inputValue = ref('')\nconst highlightedIndex = ref(-1)\n// The text input doubles as the dropdown trigger, so focus restoration is the\n// composable's `triggerRef` rather than a component-local refocus helper.\nconst {\n isOpen: dropdownOpen,\n triggerRef: inputRef,\n open: openDropdown,\n close: closeDropdown,\n} = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('root'),\n onClose: () => {\n highlightedIndex.value = -1\n },\n})\n\nconst selectionLimit = useSelectionLimit({\n count: () => props.modelValue.length,\n max: () => props.maxTags,\n})\nconst canAddMore = selectionLimit.canAddMore\n\nconst normalizedSuggestions = computed<TagSuggestion[]>(() => {\n return props.suggestions.map(s => typeof s === 'string' ? { value: s } : s)\n})\n\nconst filteredSuggestions = computed<TagSuggestion[]>(() => {\n const q = inputValue.value.trim().toLowerCase()\n if (!q) return []\n return normalizedSuggestions.value\n .filter(s => s.value.toLowerCase().startsWith(q) && !props.modelValue.includes(s.value))\n .slice(0, 8)\n})\n\nfunction categoryFor(tag: string): TagCategory | undefined {\n const colonIdx = tag.indexOf(':')\n if (colonIdx === -1) return undefined\n const prefix = tag.slice(0, colonIdx)\n return props.categories.find(c => c.prefix === prefix)\n}\n\n// 3f: a category is shown by a group-color dot (3a palette), never a semantic tint.\nconst GROUP_COLORS = [\n 'var(--mint-sample-1)', 'var(--mint-sample-2)', 'var(--mint-sample-3)', 'var(--mint-sample-4)',\n 'var(--mint-sample-5)', 'var(--mint-sample-6)', 'var(--mint-sample-7)', 'var(--mint-sample-8)',\n]\n\nfunction groupColor(category: TagCategory): string {\n return GROUP_COLORS[props.categories.indexOf(category) % GROUP_COLORS.length]\n}\n\nfunction addTag(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return\n if (!selectionLimit.canAdd()) return\n\n // If a category is active and user didn't already type a prefix, prepend it\n let final = trimmed\n if (props.activeCategory && !trimmed.includes(':')) {\n final = `${props.activeCategory}:${trimmed}`\n }\n\n if (!props.allowDuplicates && props.modelValue.includes(final)) return\n\n emit('update:modelValue', [...props.modelValue, final])\n inputValue.value = ''\n closeDropdown()\n}\n\nfunction removeTag(index: number) {\n if (props.disabled) return\n const newTags = [...props.modelValue]\n newTags.splice(index, 1)\n emit('update:modelValue', newTags)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'ArrowDown' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.min(highlightedIndex.value + 1, filteredSuggestions.value.length - 1)\n openDropdown()\n return\n }\n if (event.key === 'ArrowUp' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)\n return\n }\n if (event.key === 'Enter' || event.key === ',') {\n event.preventDefault()\n if (highlightedIndex.value >= 0 && filteredSuggestions.value[highlightedIndex.value]) {\n addTag(filteredSuggestions.value[highlightedIndex.value].value)\n } else {\n addTag(inputValue.value)\n }\n return\n }\n if (event.key === 'Escape') {\n closeDropdown(true)\n return\n }\n if (event.key === 'Backspace' && !inputValue.value && props.modelValue.length > 0) {\n removeTag(props.modelValue.length - 1)\n }\n}\n\nfunction handleFocus() {\n if (filteredSuggestions.value.length) openDropdown()\n}\n\nfunction handleBlur() {\n // Delay so a click on a suggestion fires first\n setTimeout(() => {\n closeDropdown()\n }, 120)\n}\n\nfunction handlePaste(event: ClipboardEvent) {\n event.preventDefault()\n const text = event.clipboardData?.getData('text')\n if (!text) return\n\n const tags = text.split(/[,\\n]/).map(t => t.trim()).filter(Boolean)\n const newTags = [...props.modelValue]\n\n for (const tag of tags) {\n if (!selectionLimit.canAdd(1, newTags.length)) break\n if (!props.allowDuplicates && newTags.includes(tag)) continue\n newTags.push(tag)\n }\n\n emit('update:modelValue', newTags)\n}\n\nfunction focusInput() {\n inputRef.value?.focus()\n}\n\nfunction setCategory(prefix: string) {\n emit('update:activeCategory', prefix === props.activeCategory ? '' : prefix)\n}\n\nfunction onInputEvent() {\n if (filteredSuggestions.value.length > 0) {\n openDropdown()\n } else {\n closeDropdown()\n }\n highlightedIndex.value = -1\n}\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"[\n 'mint-tags-input',\n `mint-tags-input--${size}`,\n invalid ? 'mint-tags-input--error' : '',\n disabled ? 'mint-tags-input--disabled' : '',\n categories.length ? 'mint-tags-input--categorized' : '',\n ]\"\n >\n <!-- Category switcher (only if categories defined) -->\n <div v-if=\"categories.length\" class=\"mint-tags-input__categories\">\n <button\n v-for=\"cat in categories\"\n :key=\"cat.prefix\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__category',\n `mint-tags-input__category--${cat.tone ?? 'neutral'}`,\n activeCategory === cat.prefix ? 'mint-tags-input__category--active' : '',\n ]\"\n :disabled=\"disabled\"\n @click=\"setCategory(cat.prefix)\"\n >\n <span class=\"mint-tags-input__tag-dot\" :style=\"{ background: groupColor(cat) }\" aria-hidden=\"true\" />\n {{ cat.name }}\n </button>\n </div>\n\n <div class=\"mint-tags-input__field\" @click=\"focusInput\">\n <span\n v-for=\"(tag, index) in modelValue\"\n :key=\"`${tag}-${index}`\"\n :class=\"[\n 'mint-tags-input__tag',\n `mint-tags-input__tag--${size}`,\n categoryFor(tag) ? `mint-tags-input__tag--${categoryFor(tag)?.tone ?? 'neutral'}` : '',\n ]\"\n >\n <span\n v-if=\"categoryFor(tag)\"\n class=\"mint-tags-input__tag-dot\"\n :style=\"{ background: groupColor(categoryFor(tag)!) }\"\n aria-hidden=\"true\"\n />\n {{ tag }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n :aria-label=\"`Remove ${tag}`\"\n class=\"mint-tags-input__tag-remove\"\n @click.stop=\"removeTag(index)\"\n >\n <svg class=\"mint-tags-input__tag-remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n\n <input\n ref=\"inputRef\"\n v-model=\"inputValue\"\n type=\"text\"\n :placeholder=\"modelValue.length === 0 ? placeholder : ''\"\n :disabled=\"disabled || !canAddMore\"\n :class=\"['mint-tags-input__input', `mint-tags-input__input--${size}`]\"\n @keydown=\"handleKeydown\"\n @paste=\"handlePaste\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n @input=\"onInputEvent\"\n />\n\n <!-- Autocomplete dropdown -->\n <div\n v-if=\"dropdownOpen && filteredSuggestions.length\"\n class=\"mint-tags-input__dropdown\"\n >\n <button\n v-for=\"(sug, i) in filteredSuggestions\"\n :key=\"sug.value\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__dropdown-item',\n i === highlightedIndex ? 'mint-tags-input__dropdown-item--highlighted' : '',\n ]\"\n @mousedown.prevent=\"addTag(sug.value)\"\n >\n <span>{{ sug.value }}</span>\n <span v-if=\"sug.count !== undefined\" class=\"mint-tags-input__dropdown-count\">\n {{ sug.count }}\n </span>\n </button>\n </div>\n </div>\n </div>\n</template>\n","import type { JobState, JobStateInput, JobStatus } from './types/jobs'\n\nconst ACTIVE_JOB_STATUSES = new Set<JobStatus>([\n 'awaiting_input',\n 'queued',\n 'running',\n])\nconst TERMINAL_JOB_STATUSES = new Set<JobStatus>([\n 'completed',\n 'failed',\n 'cancelled',\n])\n\nexport interface JobCapabilityInput {\n status: string\n can_cancel?: boolean | null\n can_delete?: boolean | null\n}\n\nexport interface JobCapabilities {\n can_cancel: boolean\n can_delete: boolean\n}\n\n/** Resolve action support while retaining one-cycle legacy status inference. */\nexport function resolveJobCapabilities(job: JobCapabilityInput): JobCapabilities {\n const legacyCanCancel = job.status === 'queued' || job.status === 'running'\n const legacyCanDelete = TERMINAL_JOB_STATUSES.has(job.status as JobStatus)\n return {\n can_cancel: typeof job.can_cancel === 'boolean' ? job.can_cancel : legacyCanCancel,\n can_delete: typeof job.can_delete === 'boolean' ? job.can_delete : legacyCanDelete,\n }\n}\n\n/** Clamp invalid or out-of-range progress values for safe display. */\nexport function normalizeJobPercent(value: number): number {\n if (!Number.isFinite(value)) return 0\n return Math.min(100, Math.max(0, value))\n}\n\n/** Create a detached canonical state without changing the transport input. */\nexport function normalizeJobState(job: JobStateInput): JobState {\n const capabilities = resolveJobCapabilities(job)\n return {\n ...job,\n definition_id: job.definition_id\n ?? (typeof job.metadata.definition_id === 'string' ? job.metadata.definition_id : null),\n result_status: job.result_status\n ?? (job.status === 'completed' && job.metadata.has_result === true ? 'available' : 'none'),\n result_expires_at: job.result_expires_at ?? null,\n progress: {\n ...job.progress,\n percent: normalizeJobPercent(job.progress.percent),\n },\n warnings: [...job.warnings],\n folders: [...job.folders],\n metadata: { ...job.metadata },\n ...capabilities,\n }\n}\n\nexport function isActiveJobStatus(status: JobStatus): boolean {\n return ACTIVE_JOB_STATUSES.has(status)\n}\n\nexport function isTerminalJobStatus(status: JobStatus): boolean {\n return TERMINAL_JOB_STATUSES.has(status)\n}\n\nexport function jobStatusLabel(status: JobStatus): string {\n const labels: Record<JobStatus, string> = {\n awaiting_input: 'Waiting for input',\n queued: 'Queued',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n cancelled: 'Cancelled',\n }\n return labels[status]\n}\n","import type { PlatformContext } from '../types'\n\nexport function getInjectedPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\n/** Return the platform's canonical plugin identity for the mounted frontend. */\nexport function resolveCurrentPluginId(): string | undefined {\n const pluginId = getInjectedPlatformContext()?.plugin?.id\n return typeof pluginId === 'string' && pluginId ? pluginId : undefined\n}\n\nexport function parseExperimentId(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n if (value && typeof value === 'object' && 'id' in value) {\n return parseExperimentId((value as { id?: unknown }).id)\n }\n return undefined\n}\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable, optionally grouped single-select list shared by the experiment and\n * artifact selector modals: two-line rows (title, then code + meta) with status and date\n * in a right-hand column, a filled selected row, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, reactive, ref, useId, watch } from 'vue'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\nimport type { Tone } from '../../types'\n\nexport interface ResourcePickerRow {\n /** Identifier shown as a gray pill at the start of the second line, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts after the code, joined with \" · \". */\n meta?: string[]\n /** Right column, above the date, tinted by its tone. */\n status?: { label: string; tone: Tone }\n /** Right column, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n /** When set, rows render under collapsible group headers in this order. */\n groups?: { label: string; items: T[] }[] | null\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n }>(),\n {\n groups: null,\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** A second filter row under the search. */\n advanced?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst collapsed = reactive(new Set<string>())\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst visibleGroups = computed(() =>\n props.groups?.map((group) => ({\n ...group,\n rows: collapsed.has(group.label) ? [] : group.items,\n })),\n)\n/** Keyboard order: the rows on screen, top to bottom. */\nconst flat = computed(() =>\n visibleGroups.value ? visibleGroups.value.flatMap((group) => group.rows) : props.items,\n)\nconst indexByKey = computed(() => new Map(flat.value.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = flat.value[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction toggleGroup(label: string) {\n if (collapsed.has(label)) collapsed.delete(label)\n else collapsed.add(label)\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused header, filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = flat.value\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => [props.items, props.groups],\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n <slot name=\"advanced\" />\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <template v-for=\"group in visibleGroups ?? [{ label: '', items, rows: items }]\" :key=\"group.label\">\n <button\n v-if=\"visibleGroups\"\n type=\"button\"\n class=\"mint-resource-picker__group\"\n :aria-expanded=\"!collapsed.has(group.label)\"\n @click=\"toggleGroup(group.label)\"\n >\n <svg\n class=\"mint-resource-picker__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n <span class=\"mint-resource-picker__group-label\">{{ group.label }}</span>\n <span class=\"mint-resource-picker__group-count\">{{ group.items.length }}</span>\n </button>\n <div\n v-for=\"item in group.rows\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\">{{ describe(item).title }}</span>\n <span v-if=\"describe(item).code || describe(item).meta?.length\" class=\"mint-resource-picker__meta\"\n ><span v-if=\"describe(item).code\" class=\"mint-resource-picker__code mint-exp-code mint-exp-code--sm\">{{\n describe(item).code\n }}</span\n ><span v-if=\"describe(item).meta?.length\">{{ describe(item).meta!.join(' · ') }}</span></span\n >\n </span>\n <span v-if=\"describe(item).status || describe(item).date\" class=\"mint-resource-picker__aside\">\n <span\n v-if=\"describe(item).status\"\n class=\"mint-resource-picker__status\"\n :class=\"`mint-resource-picker__status--${describe(item).status!.tone}`\"\n >{{ describe(item).status!.label }}</span\n >\n <span v-if=\"describe(item).date\" class=\"mint-resource-picker__date\">{{ describe(item).date }}</span>\n </span>\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n </div>\n </template>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable, optionally grouped single-select list shared by the experiment and\n * artifact selector modals: two-line rows (title, then code + meta) with status and date\n * in a right-hand column, a filled selected row, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, reactive, ref, useId, watch } from 'vue'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\nimport type { Tone } from '../../types'\n\nexport interface ResourcePickerRow {\n /** Identifier shown as a gray pill at the start of the second line, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts after the code, joined with \" · \". */\n meta?: string[]\n /** Right column, above the date, tinted by its tone. */\n status?: { label: string; tone: Tone }\n /** Right column, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n /** When set, rows render under collapsible group headers in this order. */\n groups?: { label: string; items: T[] }[] | null\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n }>(),\n {\n groups: null,\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** A second filter row under the search. */\n advanced?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst collapsed = reactive(new Set<string>())\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst visibleGroups = computed(() =>\n props.groups?.map((group) => ({\n ...group,\n rows: collapsed.has(group.label) ? [] : group.items,\n })),\n)\n/** Keyboard order: the rows on screen, top to bottom. */\nconst flat = computed(() =>\n visibleGroups.value ? visibleGroups.value.flatMap((group) => group.rows) : props.items,\n)\nconst indexByKey = computed(() => new Map(flat.value.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = flat.value[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction toggleGroup(label: string) {\n if (collapsed.has(label)) collapsed.delete(label)\n else collapsed.add(label)\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused header, filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = flat.value\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => [props.items, props.groups],\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n <slot name=\"advanced\" />\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <template v-for=\"group in visibleGroups ?? [{ label: '', items, rows: items }]\" :key=\"group.label\">\n <button\n v-if=\"visibleGroups\"\n type=\"button\"\n class=\"mint-resource-picker__group\"\n :aria-expanded=\"!collapsed.has(group.label)\"\n @click=\"toggleGroup(group.label)\"\n >\n <svg\n class=\"mint-resource-picker__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n <span class=\"mint-resource-picker__group-label\">{{ group.label }}</span>\n <span class=\"mint-resource-picker__group-count\">{{ group.items.length }}</span>\n </button>\n <div\n v-for=\"item in group.rows\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\">{{ describe(item).title }}</span>\n <span v-if=\"describe(item).code || describe(item).meta?.length\" class=\"mint-resource-picker__meta\"\n ><span v-if=\"describe(item).code\" class=\"mint-resource-picker__code mint-exp-code mint-exp-code--sm\">{{\n describe(item).code\n }}</span\n ><span v-if=\"describe(item).meta?.length\">{{ describe(item).meta!.join(' · ') }}</span></span\n >\n </span>\n <span v-if=\"describe(item).status || describe(item).date\" class=\"mint-resource-picker__aside\">\n <span\n v-if=\"describe(item).status\"\n class=\"mint-resource-picker__status\"\n :class=\"`mint-resource-picker__status--${describe(item).status!.tone}`\"\n >{{ describe(item).status!.label }}</span\n >\n <span v-if=\"describe(item).date\" class=\"mint-resource-picker__date\">{{ describe(item).date }}</span>\n </span>\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n </div>\n </template>\n </div>\n </div>\n</template>\n","/** Narrow an unknown value to a plain object (arrays and null excluded). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],"mappings":"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"}
|