@morscherlab/mint-sdk 1.4.0-beta.1 → 1.4.0-beta.11
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/dist/{ActionMenu-CScINahU.js → AlertBox-B2Bgr3ei.js} +40 -209
- package/dist/AlertBox-B2Bgr3ei.js.map +1 -0
- package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-mvm--GxN.js} +161 -110
- package/dist/AppSidebar-mvm--GxN.js.map +1 -0
- package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-nbJj51is.js} +2 -2
- package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-nbJj51is.js.map} +1 -1
- package/dist/ExperimentPopover-5T1fAq2L.js +337 -0
- package/dist/ExperimentPopover-5T1fAq2L.js.map +1 -0
- package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-65peG4Up.js} +198 -181
- package/dist/ExperimentSelectorModal-65peG4Up.js.map +1 -0
- package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-BtnnjWzs.js} +2 -2
- package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-BtnnjWzs.js.map} +1 -1
- package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-DO3IZ7qz.js} +9 -9
- package/dist/SettingsModal-DO3IZ7qz.js.map +1 -0
- package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
- package/dist/components/AuditTrail.vue.d.ts +1 -1
- 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 +0 -4
- package/dist/components/FilePicker.vue.d.ts +1 -1
- package/dist/components/FileUploader.vue.d.ts +2 -2
- package/dist/components/PluginIcon.vue.d.ts +2 -2
- package/dist/components/SampleSelector.vue.d.ts +6 -6
- package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
- package/dist/components/StepWizard.vue.d.ts +3 -0
- package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +1 -1
- package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
- package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
- package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -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/usePlatform.d.ts +1 -0
- package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-B8CTXagP.js} +2 -2
- package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-B8CTXagP.js.map} +1 -1
- package/dist/{data-C2PwI_dn.js → data-CgILxDLW.js} +178 -124
- package/dist/data-CgILxDLW.js.map +1 -0
- package/dist/data.js +8 -8
- package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-Cqp6qNrR.js} +3 -3
- package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-Cqp6qNrR.js.map} +1 -1
- package/dist/index.js +19 -19
- package/dist/{install-DAID6c2-.js → install-mB8-IyvO.js} +15 -14
- package/dist/{install-DAID6c2-.js.map → install-mB8-IyvO.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-DLwRl_Ql.js → lab-D5bIX426.js} +128 -147
- package/dist/lab-D5bIX426.js.map +1 -0
- package/dist/lab.js +4 -3
- package/dist/{records-BzTcxekG.js → records-B6gpM_3e.js} +472 -274
- package/dist/records-B6gpM_3e.js.map +1 -0
- package/dist/{runtime-D6gVat6r.js → runtime-D7vKpfbF.js} +27 -31
- package/dist/runtime-D7vKpfbF.js.map +1 -0
- package/dist/runtime.js +6 -6
- package/dist/{shell-5ju97nOS.js → shell-CywENwBT.js} +5 -5
- package/dist/{shell-5ju97nOS.js.map → shell-CywENwBT.js.map} +1 -1
- package/dist/shell.js +5 -5
- package/dist/styles.css +1644 -1688
- package/dist/types/componentWorkflowTypes.d.ts +2 -0
- package/dist/types/generated/platformContext.d.ts +1 -0
- package/dist/types/generated-ui.d.ts +4 -0
- package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-8yWMu-7_.js} +60 -2
- package/dist/useDropdownState-8yWMu-7_.js.map +1 -0
- package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-DHnxKFAF.js} +3 -3
- package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-DHnxKFAF.js.map} +1 -1
- package/dist/{useListReorder-CcbEYxX-.js → useListReorder-BitdUhxn.js} +109 -277
- package/dist/useListReorder-BitdUhxn.js.map +1 -0
- package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-Q8xO-cCy.js} +72 -58
- package/dist/useRackEditor-Q8xO-cCy.js.map +1 -0
- package/dist/{useRealtime-PalKue84.js → useRealtime-C3iy9QkU.js} +7 -4
- package/dist/useRealtime-C3iy9QkU.js.map +1 -0
- package/dist/useRequest-D506eHi8.js +244 -0
- package/dist/useRequest-D506eHi8.js.map +1 -0
- package/dist/utils/time.d.ts +7 -0
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +51 -2
- package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
- package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -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 +119 -13
- package/src/__tests__/components/GeneratedPluginView.test.ts +22 -1
- package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
- package/src/__tests__/components/PluginWorkspaceView.test.ts +7 -0
- package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
- package/src/__tests__/components/SampleSelector.test.ts +13 -8
- package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
- 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__/styles/baseControlsRules.test.ts +6 -2
- package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
- package/src/__tests__/styles/cssTokens.test.ts +2 -2
- package/src/__tests__/styles/menusShellRefresh.test.ts +14 -10
- package/src/__tests__/styles/v2AuditRules.test.ts +96 -0
- package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
- package/src/__tests__/utils/time.test.ts +18 -1
- 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.story.vue +47 -12
- package/src/components/AppTopBar.vue +118 -114
- 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/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 +40 -36
- package/src/components/ExperimentSelectorModal.vue +124 -110
- package/src/components/FormField.story.vue +8 -48
- package/src/components/GeneratedPluginView.vue +7 -1
- package/src/components/GeneratedResultRenderer.vue +3 -4
- package/src/components/InstrumentStateBadge.vue +1 -1
- package/src/components/JobsStatusTray.vue +1 -1
- 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.story.vue +1 -1
- package/src/components/RuntimeUpdateNotice.vue +1 -1
- package/src/components/SampleSelector.story.vue +1 -1
- package/src/components/SampleSelector.vue +27 -37
- package/src/components/SampleSelectorGroupNode.vue +1 -1
- package/src/components/SectionCard.story.vue +2 -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 +2 -2
- 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/WellPlate.story.vue +3 -1
- package/src/components/WellPlate.vue +7 -0
- package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
- package/src/components/internal/DatePickerDateInternal.vue +16 -40
- package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
- package/src/components/internal/DatePickerTimeInternal.vue +5 -8
- package/src/components/internal/ResourcePickerListInternal.vue +45 -85
- package/src/components/internal/SelectMultipleInternal.vue +182 -65
- package/src/components/internal/SelectSearchableInternal.vue +2 -3
- 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/usePluginWorkspace.ts +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 +7 -5
- package/src/styles/components/app-page-selector.css +3 -1
- 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 +57 -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 +28 -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 +80 -92
- package/src/styles/components/datetime-picker.css +31 -43
- 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 +75 -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 +31 -25
- package/src/styles/components/modal.css +4 -6
- 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/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 +95 -79
- package/src/styles/components/schedule-calendar.css +8 -8
- package/src/styles/components/searchable-select.css +12 -12
- package/src/styles/components/section-card.css +30 -47
- 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 +36 -21
- package/src/styles/components/toast.css +12 -10
- package/src/styles/components/toggle.css +1 -11
- package/src/styles/components/tooltip.css +10 -9
- package/src/styles/components/unit-input.css +8 -7
- package/src/styles/components/well-plate.css +9 -2
- package/src/styles/variables.css +118 -77
- package/src/types/componentWorkflowTypes.ts +2 -0
- package/src/types/generated/platformContext.ts +1 -0
- package/src/types/generated-ui.ts +4 -0
- 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/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/useListReorder-CcbEYxX-.js.map +0 -1
- package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
- 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":"BaseModal-DfRIuVoj.js","names":["$slots"],"sources":["../src/components/BaseButton.vue","../src/components/BaseButton.vue","../src/composables/useEventListener.ts","../src/composables/useFocusTrap.ts","../src/components/BaseModal.vue","../src/components/BaseModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a styled `<button>` with variant, size, loading spinner, and full-width options.\n * With `icon` and no default slot it is a square icon-only button; `label` is then its accessible name.\n *\n * @example\n * ```vue\n * <BaseButton variant=\"primary\" :loading=\"busy\">Save</BaseButton>\n * <BaseButton :icon=\"Plus\">Add sample</BaseButton>\n * <BaseButton variant=\"ghost\" :icon=\"Trash2\" label=\"Delete\" />\n * ```\n */\nimport { computed, useSlots, type Component } from 'vue'\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n /** Icon component (for example a lucide icon) rendered before the label, or alone when there is no default slot. */\n icon?: Component\n /** Accessible name and tooltip of an icon-only button. */\n label?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n icon: undefined,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst slots = useSlots()\nconst iconOnly = computed(() => Boolean(props.icon) && !slots.default)\nconst block = computed(() => (iconOnly.value ? 'mint-icon-button' : 'mint-button'))\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :aria-label=\"iconOnly ? label : undefined\"\n :title=\"iconOnly ? label : undefined\"\n :class=\"[\n block,\n `${block}--${variant}`,\n `${block}--${size}`,\n fullWidth && !iconOnly ? 'mint-button--full-width' : '',\n (disabled || loading) ? `${block}--disabled` : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n :class=\"iconOnly ? ['mint-icon-button__spinner', `mint-icon-button__icon--${size}`] : 'mint-button__spinner'\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <span v-if=\"iconOnly && !loading\" :class=\"`mint-icon-button__icon--${size}`\">\n <component :is=\"icon\" aria-hidden=\"true\" />\n </span>\n <template v-if=\"!iconOnly\">\n <component :is=\"icon\" v-if=\"icon\" class=\"mint-button__icon\" aria-hidden=\"true\" />\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </template>\n </button>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled `<button>` with variant, size, loading spinner, and full-width options.\n * With `icon` and no default slot it is a square icon-only button; `label` is then its accessible name.\n *\n * @example\n * ```vue\n * <BaseButton variant=\"primary\" :loading=\"busy\">Save</BaseButton>\n * <BaseButton :icon=\"Plus\">Add sample</BaseButton>\n * <BaseButton variant=\"ghost\" :icon=\"Trash2\" label=\"Delete\" />\n * ```\n */\nimport { computed, useSlots, type Component } from 'vue'\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n /** Icon component (for example a lucide icon) rendered before the label, or alone when there is no default slot. */\n icon?: Component\n /** Accessible name and tooltip of an icon-only button. */\n label?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n icon: undefined,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst slots = useSlots()\nconst iconOnly = computed(() => Boolean(props.icon) && !slots.default)\nconst block = computed(() => (iconOnly.value ? 'mint-icon-button' : 'mint-button'))\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :aria-label=\"iconOnly ? label : undefined\"\n :title=\"iconOnly ? label : undefined\"\n :class=\"[\n block,\n `${block}--${variant}`,\n `${block}--${size}`,\n fullWidth && !iconOnly ? 'mint-button--full-width' : '',\n (disabled || loading) ? `${block}--disabled` : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n :class=\"iconOnly ? ['mint-icon-button__spinner', `mint-icon-button__icon--${size}`] : 'mint-button__spinner'\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <span v-if=\"iconOnly && !loading\" :class=\"`mint-icon-button__icon--${size}`\">\n <component :is=\"icon\" aria-hidden=\"true\" />\n </span>\n <template v-if=\"!iconOnly\">\n <component :is=\"icon\" v-if=\"icon\" class=\"mint-button__icon\" aria-hidden=\"true\" />\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </template>\n </button>\n</template>\n","import { isRef, onMounted, onUnmounted, watch, type Ref } from 'vue'\n\nexport type EventTargetGetter<TTarget extends EventTarget = EventTarget> =\n () => TTarget | null | undefined\n\nexport type EventTargetLike<TTarget extends EventTarget = EventTarget> =\n | TTarget\n | Ref<TTarget | null | undefined>\n | EventTargetGetter<TTarget>\n | null\n | undefined\n\nexport type EventListenerEnabled = boolean | Ref<boolean>\n\nexport interface UseEventListenerObjectOptions extends AddEventListenerOptions {\n enabled?: EventListenerEnabled\n}\n\nexport type UseEventListenerOptions = boolean | UseEventListenerObjectOptions\nexport type EventListenerStop = () => void\n\nexport type EventMapFor<TTarget extends EventTarget> =\n TTarget extends Window\n ? WindowEventMap\n : TTarget extends Document\n ? DocumentEventMap\n : TTarget extends HTMLElement\n ? HTMLElementEventMap\n : Record<string, Event>\n\nexport type EventFor<\n TTarget extends EventTarget,\n TType extends string,\n> = TType extends keyof EventMapFor<TTarget>\n ? EventMapFor<TTarget>[TType]\n : Event\n\n/** Bind a DOM event listener on mount, remove it on unmount, and rebind when a ref target changes. */\nexport function useEventListener<\n TTarget extends EventTarget = EventTarget,\n TType extends string = string,\n>(\n target: EventTargetLike<TTarget>,\n type: TType,\n listener: (event: EventFor<TTarget, TType>) => void,\n options?: UseEventListenerOptions,\n): EventListenerStop {\n let stopCurrent: EventListenerStop | undefined\n let mounted = false\n\n function stop(): void {\n stopCurrent?.()\n stopCurrent = undefined\n }\n\n function start(): void {\n stop()\n if (!mounted || !isEnabled(options)) return\n const resolvedTarget = resolveEventTarget(target)\n if (!resolvedTarget) return\n\n const eventListener = listener as EventListener\n const eventOptions = getEventOptions(options)\n resolvedTarget.addEventListener(type, eventListener, eventOptions)\n stopCurrent = () => {\n resolvedTarget.removeEventListener(type, eventListener, eventOptions)\n }\n }\n\n onMounted(() => {\n mounted = true\n start()\n })\n\n if (isRef(target)) {\n watch(target, start, { flush: 'post' })\n }\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) {\n watch(enabled, start, { flush: 'post' })\n }\n\n onUnmounted(() => {\n mounted = false\n stop()\n })\n\n return stop\n}\n\nfunction resolveEventTarget(target: EventTargetLike): EventTarget | null | undefined {\n if (isRef(target)) return target.value\n if (typeof target === 'function') return target()\n return target\n}\n\nfunction getEnabledOption(options: UseEventListenerOptions | undefined): EventListenerEnabled | undefined {\n return typeof options === 'object' ? options.enabled : undefined\n}\n\nfunction isEnabled(options: UseEventListenerOptions | undefined): boolean {\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) return enabled.value\n return enabled ?? true\n}\n\nfunction getEventOptions(options: UseEventListenerOptions | undefined): boolean | AddEventListenerOptions | undefined {\n if (typeof options !== 'object') return options\n const { enabled: _enabled, ...eventOptions } = options\n return eventOptions\n}\n","import { nextTick, watch, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseFocusTrapOptions {\n /** Ref to the trap's container element. Focusable elements are queried within it. */\n containerRef: Ref<HTMLElement | null>\n /** Reactive flag — the trap activates when this becomes `true` and releases when it becomes `false`. */\n active: Ref<boolean>\n /** Restore focus to the element that was focused before activation, when the trap releases. Default `true`. */\n restoreFocus?: boolean\n}\n\nexport interface UseFocusTrapReturn {\n /** Focusable descendants of the container, in DOM order, excluding roving-tabindex (`tabindex=\"-1\"`) elements. */\n getFocusableElements: () => HTMLElement[]\n}\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\n/**\n * Traps Tab focus within a container while `active` is true: Tab wraps from the last\n * focusable element back to the first (and Shift+Tab from the first to the last), the\n * first focusable element (or the container itself, if none) receives focus when the\n * trap activates, an `[autofocus]` descendant taking precedence, and focus returns to\n * whatever was focused beforehand when it releases.\n * Used by BaseModal and WellEditPopupInternal.\n */\nexport function useFocusTrap(options: UseFocusTrapOptions): UseFocusTrapReturn {\n const { containerRef, active } = options\n const restoreFocus = options.restoreFocus ?? true\n let previouslyFocused: HTMLElement | null = null\n\n function getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n // Roving tabindex (inactive tabs/rail items) stays out of the Tab cycle. Checking\n // the attribute directly (rather than the `.tabIndex` IDL property) avoids relying\n // on a browser/engine's default-tabindex computation for freshly-patched elements.\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n .filter((el) => el.getAttribute('tabindex') !== '-1')\n }\n\n function handleKeydown(event: KeyboardEvent) {\n if (event.key !== 'Tab' || !active.value || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n }\n\n // `immediate` so a container mounted already active (`v-if` + a constant\n // `modelValue`) still takes focus. `flush: 'sync'` so releasing the trap from `onBeforeUnmount` restores focus\n // before the component's reactive scope is torn down — a batched (default\n // 'pre') watcher would be scheduled but never flushed once that scope stops.\n watch(active, async (isActive) => {\n if (isActive) {\n previouslyFocused = document.activeElement as HTMLElement | null\n await nextTick()\n // Like <dialog>: an [autofocus] descendant wins over the first focusable element.\n const target = containerRef.value?.querySelector<HTMLElement>('[autofocus]') ?? getFocusableElements()[0]\n if (target) {\n target.focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n if (restoreFocus) previouslyFocused?.focus()\n previouslyFocused = null\n }\n }, { flush: 'sync', immediate: true })\n\n useEventListener(() => document, 'keydown', handleKeydown)\n\n return { getFocusableElements }\n}\n","<script lang=\"ts\">\n/** Open modals, oldest first; shared by every BaseModal instance. */\nconst openModals: object[] = []\n</script>\n\n<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, toRef, watch, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\nimport { useFocusTrap } from '../composables/useFocusTrap'\n\nexport interface Props {\n open: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\n/** Roving tabindex; with no active tab (e.g. a search is showing) the first tab stays reachable. */\nfunction isTabStop(tab: ModalTab, index: number): boolean {\n return activeTabMeta.value ? tab.id === props.activeTab : index === 0\n}\n\n/** A rail section heading goes before the first tab of each run of one `section`. */\nfunction startsSection(index: number): boolean {\n const section = props.tabs[index].section\n return !!section && section !== props.tabs[index - 1]?.section\n}\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\n\nuseFocusTrap({ containerRef, active: toRef(props, 'open') })\n\nwatch(() => props.open, (isOpen) => {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n})\n\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n}, { immediate: true })\n\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.open && openModals[openModals.length - 1] === self) {\n close()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:open', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nuseEventListener(() => document, 'keydown', handleEscapeKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"open\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-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 <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"(tab, index) in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <template v-for=\"(tab, index) in tabs\" :key=\"tab.id\">\n <template v-if=\"startsSection(index)\">\n <div v-if=\"index > 0\" class=\"mint-modal__rail-divider\" aria-hidden=\"true\" />\n <span class=\"mint-modal__rail-section\" aria-hidden=\"true\">{{ tab.section }}</span>\n </template>\n <button\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </template>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"$slots['pane-header'] || activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <!-- Replaces the default title + subtitle, e.g. to add pane actions. -->\n <slot name=\"pane-header\" :tab=\"activeTabMeta\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta?.label }}</h4>\n <p v-if=\"activeTabMeta?.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </slot>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n","<script lang=\"ts\">\n/** Open modals, oldest first; shared by every BaseModal instance. */\nconst openModals: object[] = []\n</script>\n\n<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, toRef, watch, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\nimport { useFocusTrap } from '../composables/useFocusTrap'\n\nexport interface Props {\n open: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\n/** Roving tabindex; with no active tab (e.g. a search is showing) the first tab stays reachable. */\nfunction isTabStop(tab: ModalTab, index: number): boolean {\n return activeTabMeta.value ? tab.id === props.activeTab : index === 0\n}\n\n/** A rail section heading goes before the first tab of each run of one `section`. */\nfunction startsSection(index: number): boolean {\n const section = props.tabs[index].section\n return !!section && section !== props.tabs[index - 1]?.section\n}\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\n\nuseFocusTrap({ containerRef, active: toRef(props, 'open') })\n\nwatch(() => props.open, (isOpen) => {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n})\n\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n}, { immediate: true })\n\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.open && openModals[openModals.length - 1] === self) {\n close()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:open', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nuseEventListener(() => document, 'keydown', handleEscapeKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"open\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-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 <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"(tab, index) in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <template v-for=\"(tab, index) in tabs\" :key=\"tab.id\">\n <template v-if=\"startsSection(index)\">\n <div v-if=\"index > 0\" class=\"mint-modal__rail-divider\" aria-hidden=\"true\" />\n <span class=\"mint-modal__rail-section\" aria-hidden=\"true\">{{ tab.section }}</span>\n </template>\n <button\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </template>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"$slots['pane-header'] || activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <!-- Replaces the default title + subtitle, e.g. to add pane actions. -->\n <slot name=\"pane-header\" :tab=\"activeTabMeta\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta?.label }}</h4>\n <p v-if=\"activeTabMeta?.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </slot>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { a as __exportAll } from "./BaseModal-DfRIuVoj.js";
|
|
2
|
-
import { D as useDropdownState } from "./records-BzTcxekG.js";
|
|
3
|
-
import { t as ConfirmDialog_default } from "./ConfirmDialog-CJ7hqYUP.js";
|
|
4
|
-
import { r as format } from "./experimentStatus-BZmU4czV.js";
|
|
5
|
-
import { computed, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onUnmounted, openBlock, ref, toDisplayString, unref, useTemplateRef, watch, withModifiers } from "vue";
|
|
6
|
-
//#region src/components/ExperimentPopover.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
-
var _hoisted_1 = {
|
|
8
|
-
ref: "popover",
|
|
9
|
-
class: "mint-experiment-popover"
|
|
10
|
-
};
|
|
11
|
-
var _hoisted_2 = [
|
|
12
|
-
"title",
|
|
13
|
-
"aria-label",
|
|
14
|
-
"aria-busy",
|
|
15
|
-
"aria-expanded"
|
|
16
|
-
];
|
|
17
|
-
var _hoisted_3 = {
|
|
18
|
-
key: 0,
|
|
19
|
-
class: "mint-experiment-popover__trigger-skeleton",
|
|
20
|
-
"aria-hidden": "true"
|
|
21
|
-
};
|
|
22
|
-
var _hoisted_4 = {
|
|
23
|
-
key: 1,
|
|
24
|
-
class: "mint-experiment-popover__trigger-text"
|
|
25
|
-
};
|
|
26
|
-
var _hoisted_5 = {
|
|
27
|
-
key: 2,
|
|
28
|
-
class: "mint-experiment-popover__trigger-text"
|
|
29
|
-
};
|
|
30
|
-
var _hoisted_6 = {
|
|
31
|
-
key: 3,
|
|
32
|
-
class: "mint-experiment-popover__trigger-code"
|
|
33
|
-
};
|
|
34
|
-
var _hoisted_7 = {
|
|
35
|
-
key: 4,
|
|
36
|
-
class: "mint-experiment-popover__trigger-text"
|
|
37
|
-
};
|
|
38
|
-
var _hoisted_8 = ["disabled", "title"];
|
|
39
|
-
var _hoisted_9 = {
|
|
40
|
-
key: 0,
|
|
41
|
-
class: "mint-experiment-popover__spinner--inline"
|
|
42
|
-
};
|
|
43
|
-
var _hoisted_10 = {
|
|
44
|
-
key: 1,
|
|
45
|
-
class: "mint-experiment-popover__save-trigger-icon",
|
|
46
|
-
"aria-hidden": "true",
|
|
47
|
-
fill: "none",
|
|
48
|
-
stroke: "currentColor",
|
|
49
|
-
viewBox: "0 0 24 24"
|
|
50
|
-
};
|
|
51
|
-
var _hoisted_11 = {
|
|
52
|
-
key: 2,
|
|
53
|
-
class: "mint-experiment-popover__save-trigger-icon",
|
|
54
|
-
"aria-hidden": "true",
|
|
55
|
-
fill: "none",
|
|
56
|
-
stroke: "currentColor",
|
|
57
|
-
viewBox: "0 0 24 24"
|
|
58
|
-
};
|
|
59
|
-
var _hoisted_12 = {
|
|
60
|
-
key: 0,
|
|
61
|
-
class: "mint-experiment-popover__panel"
|
|
62
|
-
};
|
|
63
|
-
var _hoisted_13 = { class: "mint-experiment-popover__header" };
|
|
64
|
-
var _hoisted_14 = { class: "mint-experiment-popover__subtitle" };
|
|
65
|
-
var _hoisted_15 = {
|
|
66
|
-
key: 0,
|
|
67
|
-
class: "mint-experiment-popover__body"
|
|
68
|
-
};
|
|
69
|
-
var _hoisted_16 = { class: "mint-experiment-popover__card-actions" };
|
|
70
|
-
var _hoisted_17 = {
|
|
71
|
-
key: 1,
|
|
72
|
-
class: "mint-experiment-popover__body"
|
|
73
|
-
};
|
|
74
|
-
var _hoisted_18 = {
|
|
75
|
-
class: "mint-experiment-popover__card mint-experiment-popover__card--error",
|
|
76
|
-
role: "alert"
|
|
77
|
-
};
|
|
78
|
-
var _hoisted_19 = { class: "mint-experiment-popover__card-info" };
|
|
79
|
-
var _hoisted_20 = { class: "mint-experiment-popover__card-message" };
|
|
80
|
-
var _hoisted_21 = { class: "mint-experiment-popover__card-actions" };
|
|
81
|
-
var _hoisted_22 = {
|
|
82
|
-
key: 2,
|
|
83
|
-
class: "mint-experiment-popover__body"
|
|
84
|
-
};
|
|
85
|
-
var _hoisted_23 = {
|
|
86
|
-
key: 3,
|
|
87
|
-
class: "mint-experiment-popover__body"
|
|
88
|
-
};
|
|
89
|
-
var _hoisted_24 = { class: "mint-experiment-popover__card" };
|
|
90
|
-
var _hoisted_25 = { class: "mint-experiment-popover__card-info" };
|
|
91
|
-
var _hoisted_26 = {
|
|
92
|
-
key: 0,
|
|
93
|
-
class: "mint-experiment-popover__card-code"
|
|
94
|
-
};
|
|
95
|
-
var _hoisted_27 = { class: "mint-experiment-popover__card-name" };
|
|
96
|
-
var _hoisted_28 = {
|
|
97
|
-
key: 1,
|
|
98
|
-
class: "mint-experiment-popover__card-status"
|
|
99
|
-
};
|
|
100
|
-
var _hoisted_29 = { class: "mint-experiment-popover__card-actions" };
|
|
101
|
-
var ExperimentPopover_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
102
|
-
__name: "ExperimentPopover",
|
|
103
|
-
props: {
|
|
104
|
-
experimentName: {},
|
|
105
|
-
experimentCode: {},
|
|
106
|
-
experimentStatus: {},
|
|
107
|
-
isResolving: {
|
|
108
|
-
type: Boolean,
|
|
109
|
-
default: false
|
|
110
|
-
},
|
|
111
|
-
error: {},
|
|
112
|
-
showSave: {
|
|
113
|
-
type: Boolean,
|
|
114
|
-
default: false
|
|
115
|
-
},
|
|
116
|
-
showDetach: {
|
|
117
|
-
type: Boolean,
|
|
118
|
-
default: false
|
|
119
|
-
},
|
|
120
|
-
saveDisabled: {
|
|
121
|
-
type: Boolean,
|
|
122
|
-
default: false
|
|
123
|
-
},
|
|
124
|
-
saveLoading: {
|
|
125
|
-
type: Boolean,
|
|
126
|
-
default: false
|
|
127
|
-
},
|
|
128
|
-
saveSuccessMessage: {},
|
|
129
|
-
saveDisabledMessage: {},
|
|
130
|
-
confirmSave: {
|
|
131
|
-
type: Boolean,
|
|
132
|
-
default: true
|
|
133
|
-
},
|
|
134
|
-
confirmTitle: {},
|
|
135
|
-
confirmMessage: {}
|
|
136
|
-
},
|
|
137
|
-
emits: [
|
|
138
|
-
"select",
|
|
139
|
-
"save",
|
|
140
|
-
"detach"
|
|
141
|
-
],
|
|
142
|
-
setup(__props, { emit: __emit }) {
|
|
143
|
-
/** Floating popover showing the active experiment with save, detach, and select actions. */
|
|
144
|
-
const props = __props;
|
|
145
|
-
const isUnresolved = computed(() => props.isResolving || !!props.error);
|
|
146
|
-
const hasExperiment = computed(() => !!props.experimentName || !!props.experimentCode);
|
|
147
|
-
const panelSubtitle = computed(() => {
|
|
148
|
-
if (props.isResolving) return "Loading experiment…";
|
|
149
|
-
if (props.error) return "Could not load this experiment";
|
|
150
|
-
return hasExperiment.value ? "Linked experiment context" : "Link to an MINT experiment";
|
|
151
|
-
});
|
|
152
|
-
const triggerLabel = computed(() => {
|
|
153
|
-
if (props.isResolving) return "Loading experiment";
|
|
154
|
-
if (props.error) return "Experiment unavailable";
|
|
155
|
-
return props.experimentName || props.experimentCode || "No experiment";
|
|
156
|
-
});
|
|
157
|
-
const emit = __emit;
|
|
158
|
-
const { isOpen, close, toggle } = useDropdownState({
|
|
159
|
-
rootRef: useTemplateRef("popover"),
|
|
160
|
-
triggerRef: useTemplateRef("trigger"),
|
|
161
|
-
closeOnEscape: false
|
|
162
|
-
});
|
|
163
|
-
const showSuccess = ref(false);
|
|
164
|
-
const showConfirm = ref(false);
|
|
165
|
-
function handleTriggerClick() {
|
|
166
|
-
if (!hasExperiment.value && !isUnresolved.value) {
|
|
167
|
-
handleSelect();
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
toggle();
|
|
171
|
-
}
|
|
172
|
-
function handleSelect() {
|
|
173
|
-
emit("select");
|
|
174
|
-
close();
|
|
175
|
-
}
|
|
176
|
-
function handleSave() {
|
|
177
|
-
if (props.saveDisabled || props.saveLoading) return;
|
|
178
|
-
if (props.confirmSave) showConfirm.value = true;
|
|
179
|
-
else emit("save");
|
|
180
|
-
}
|
|
181
|
-
function handleConfirmSave() {
|
|
182
|
-
showConfirm.value = false;
|
|
183
|
-
emit("save");
|
|
184
|
-
}
|
|
185
|
-
function handleDetach() {
|
|
186
|
-
emit("detach");
|
|
187
|
-
close();
|
|
188
|
-
}
|
|
189
|
-
let successTimer = null;
|
|
190
|
-
watch(() => props.saveSuccessMessage, (msg) => {
|
|
191
|
-
if (successTimer) clearTimeout(successTimer);
|
|
192
|
-
if (msg) {
|
|
193
|
-
showSuccess.value = true;
|
|
194
|
-
successTimer = setTimeout(() => {
|
|
195
|
-
showSuccess.value = false;
|
|
196
|
-
successTimer = null;
|
|
197
|
-
}, 3e3);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
onUnmounted(() => {
|
|
201
|
-
if (successTimer) clearTimeout(successTimer);
|
|
202
|
-
});
|
|
203
|
-
return (_ctx, _cache) => {
|
|
204
|
-
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
205
|
-
createElementVNode("div", { class: normalizeClass(["mint-experiment-popover__split", { "mint-experiment-popover__split--with-save": __props.showSave && __props.experimentName }]) }, [createElementVNode("button", {
|
|
206
|
-
ref: "trigger",
|
|
207
|
-
type: "button",
|
|
208
|
-
class: normalizeClass([
|
|
209
|
-
"mint-experiment-popover__trigger",
|
|
210
|
-
{ "mint-experiment-popover__trigger--active": unref(isOpen) },
|
|
211
|
-
{ "mint-experiment-popover__trigger--empty": !isUnresolved.value && !hasExperiment.value },
|
|
212
|
-
{ "mint-experiment-popover__trigger--loading": __props.isResolving },
|
|
213
|
-
{ "mint-experiment-popover__trigger--error": !__props.isResolving && !!__props.error }
|
|
214
|
-
]),
|
|
215
|
-
title: isUnresolved.value ? triggerLabel.value : __props.experimentName || __props.experimentCode || void 0,
|
|
216
|
-
"aria-label": isUnresolved.value ? triggerLabel.value : void 0,
|
|
217
|
-
"aria-busy": __props.isResolving || void 0,
|
|
218
|
-
"aria-expanded": unref(isOpen),
|
|
219
|
-
onClick: withModifiers(handleTriggerClick, ["stop"])
|
|
220
|
-
}, [
|
|
221
|
-
_cache[1] || (_cache[1] = createElementVNode("svg", {
|
|
222
|
-
class: "mint-experiment-popover__trigger-icon",
|
|
223
|
-
"aria-hidden": "true",
|
|
224
|
-
fill: "none",
|
|
225
|
-
stroke: "currentColor",
|
|
226
|
-
viewBox: "0 0 24 24"
|
|
227
|
-
}, [createElementVNode("path", {
|
|
228
|
-
"stroke-linecap": "round",
|
|
229
|
-
"stroke-linejoin": "round",
|
|
230
|
-
"stroke-width": "1.75",
|
|
231
|
-
d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
232
|
-
})], -1)),
|
|
233
|
-
__props.isResolving ? (openBlock(), createElementBlock("span", _hoisted_3)) : __props.error ? (openBlock(), createElementBlock("span", _hoisted_4, "Experiment unavailable")) : __props.experimentName ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(__props.experimentName), 1)) : __props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_6, toDisplayString(__props.experimentCode), 1)) : (openBlock(), createElementBlock("span", _hoisted_7, "No experiment")),
|
|
234
|
-
_cache[2] || (_cache[2] = createElementVNode("svg", {
|
|
235
|
-
class: "mint-experiment-popover__trigger-chevron",
|
|
236
|
-
"aria-hidden": "true",
|
|
237
|
-
viewBox: "0 0 24 24",
|
|
238
|
-
fill: "none",
|
|
239
|
-
stroke: "currentColor",
|
|
240
|
-
"stroke-width": "2",
|
|
241
|
-
"stroke-linecap": "round",
|
|
242
|
-
"stroke-linejoin": "round"
|
|
243
|
-
}, [createElementVNode("path", { d: "m6 9 6 6 6-6" })], -1))
|
|
244
|
-
], 10, _hoisted_2), __props.showSave && __props.experimentName ? (openBlock(), createElementBlock("button", {
|
|
245
|
-
key: 0,
|
|
246
|
-
type: "button",
|
|
247
|
-
class: normalizeClass([
|
|
248
|
-
"mint-experiment-popover__save-trigger",
|
|
249
|
-
{ "mint-experiment-popover__save-trigger--loading": __props.saveLoading },
|
|
250
|
-
{ "mint-experiment-popover__save-trigger--success": showSuccess.value },
|
|
251
|
-
{ "mint-experiment-popover__save-trigger--disabled": __props.saveDisabled && !showSuccess.value }
|
|
252
|
-
]),
|
|
253
|
-
disabled: __props.saveDisabled && !showSuccess.value,
|
|
254
|
-
title: __props.saveDisabled && __props.saveDisabledMessage ? __props.saveDisabledMessage : showSuccess.value && __props.saveSuccessMessage ? __props.saveSuccessMessage : "Save to Experiment",
|
|
255
|
-
"aria-label": "Save to experiment",
|
|
256
|
-
onClick: withModifiers(handleSave, ["stop"])
|
|
257
|
-
}, [__props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_9)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_10, [..._cache[3] || (_cache[3] = [createElementVNode("path", {
|
|
258
|
-
"stroke-linecap": "round",
|
|
259
|
-
"stroke-linejoin": "round",
|
|
260
|
-
"stroke-width": "2.5",
|
|
261
|
-
d: "M5 13l4 4L19 7"
|
|
262
|
-
}, null, -1)])])) : (openBlock(), createElementBlock("svg", _hoisted_11, [..._cache[4] || (_cache[4] = [createElementVNode("path", {
|
|
263
|
-
"stroke-linecap": "round",
|
|
264
|
-
"stroke-linejoin": "round",
|
|
265
|
-
"stroke-width": "2",
|
|
266
|
-
d: "M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
|
|
267
|
-
}, null, -1)])]))], 10, _hoisted_8)) : createCommentVNode("", true)], 2),
|
|
268
|
-
unref(isOpen) ? (openBlock(), createElementBlock("div", _hoisted_12, [createElementVNode("div", _hoisted_13, [_cache[5] || (_cache[5] = createElementVNode("div", { class: "mint-experiment-popover__title" }, "Experiment", -1)), createElementVNode("div", _hoisted_14, toDisplayString(panelSubtitle.value), 1)]), __props.isResolving ? (openBlock(), createElementBlock("div", _hoisted_15, [_cache[6] || (_cache[6] = createStaticVNode("<div class=\"mint-experiment-popover__card\" aria-busy=\"true\"><div class=\"mint-experiment-popover__card-icon\"><svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.75\" d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"></path></svg></div><div class=\"mint-experiment-popover__card-info\"><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--code\"></span><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--name\"></span><span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--status\"></span></div></div>", 1)), createElementVNode("div", _hoisted_16, [createElementVNode("button", {
|
|
269
|
-
type: "button",
|
|
270
|
-
class: "mint-experiment-popover__change-btn",
|
|
271
|
-
onClick: handleSelect
|
|
272
|
-
}, " Change "), __props.showDetach ? (openBlock(), createElementBlock("button", {
|
|
273
|
-
key: 0,
|
|
274
|
-
type: "button",
|
|
275
|
-
class: "mint-experiment-popover__detach-btn",
|
|
276
|
-
onClick: handleDetach
|
|
277
|
-
}, " Detach ")) : createCommentVNode("", true)])])) : __props.error ? (openBlock(), createElementBlock("div", _hoisted_17, [createElementVNode("div", _hoisted_18, [_cache[8] || (_cache[8] = createElementVNode("div", { class: "mint-experiment-popover__card-icon mint-experiment-popover__card-icon--error" }, [createElementVNode("svg", {
|
|
278
|
-
fill: "none",
|
|
279
|
-
stroke: "currentColor",
|
|
280
|
-
viewBox: "0 0 24 24"
|
|
281
|
-
}, [createElementVNode("path", {
|
|
282
|
-
"stroke-linecap": "round",
|
|
283
|
-
"stroke-linejoin": "round",
|
|
284
|
-
"stroke-width": "1.75",
|
|
285
|
-
d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
|
|
286
|
-
})])], -1)), createElementVNode("div", _hoisted_19, [_cache[7] || (_cache[7] = createElementVNode("div", { class: "mint-experiment-popover__card-name" }, "Experiment unavailable", -1)), createElementVNode("div", _hoisted_20, toDisplayString(__props.error), 1)])]), createElementVNode("div", _hoisted_21, [createElementVNode("button", {
|
|
287
|
-
type: "button",
|
|
288
|
-
class: "mint-experiment-popover__change-btn",
|
|
289
|
-
onClick: handleSelect
|
|
290
|
-
}, " Change "), __props.showDetach ? (openBlock(), createElementBlock("button", {
|
|
291
|
-
key: 0,
|
|
292
|
-
type: "button",
|
|
293
|
-
class: "mint-experiment-popover__detach-btn",
|
|
294
|
-
onClick: handleDetach
|
|
295
|
-
}, " Detach ")) : createCommentVNode("", true)])])) : !__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_22, [createElementVNode("button", {
|
|
296
|
-
type: "button",
|
|
297
|
-
class: "mint-experiment-popover__select-btn",
|
|
298
|
-
onClick: handleSelect
|
|
299
|
-
}, [..._cache[9] || (_cache[9] = [createElementVNode("svg", {
|
|
300
|
-
width: "14",
|
|
301
|
-
height: "14",
|
|
302
|
-
fill: "none",
|
|
303
|
-
stroke: "currentColor",
|
|
304
|
-
viewBox: "0 0 24 24"
|
|
305
|
-
}, [createElementVNode("path", {
|
|
306
|
-
"stroke-linecap": "round",
|
|
307
|
-
"stroke-linejoin": "round",
|
|
308
|
-
"stroke-width": "2",
|
|
309
|
-
d: "M12 4v16m8-8H4"
|
|
310
|
-
})], -1), createTextVNode(" Select Experiment ", -1)])])])) : (openBlock(), createElementBlock("div", _hoisted_23, [createElementVNode("div", _hoisted_24, [_cache[10] || (_cache[10] = createElementVNode("div", { class: "mint-experiment-popover__card-icon" }, [createElementVNode("svg", {
|
|
311
|
-
fill: "none",
|
|
312
|
-
stroke: "currentColor",
|
|
313
|
-
viewBox: "0 0 24 24"
|
|
314
|
-
}, [createElementVNode("path", {
|
|
315
|
-
"stroke-linecap": "round",
|
|
316
|
-
"stroke-linejoin": "round",
|
|
317
|
-
"stroke-width": "1.75",
|
|
318
|
-
d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
319
|
-
})])], -1)), createElementVNode("div", _hoisted_25, [
|
|
320
|
-
__props.experimentCode ? (openBlock(), createElementBlock("span", _hoisted_26, toDisplayString(__props.experimentCode), 1)) : createCommentVNode("", true),
|
|
321
|
-
createElementVNode("div", _hoisted_27, toDisplayString(__props.experimentName), 1),
|
|
322
|
-
__props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_28, toDisplayString(unref(format)(__props.experimentStatus)), 1)) : createCommentVNode("", true)
|
|
323
|
-
])]), createElementVNode("div", _hoisted_29, [createElementVNode("button", {
|
|
324
|
-
type: "button",
|
|
325
|
-
class: "mint-experiment-popover__change-btn",
|
|
326
|
-
onClick: handleSelect
|
|
327
|
-
}, " Change "), __props.showDetach ? (openBlock(), createElementBlock("button", {
|
|
328
|
-
key: 0,
|
|
329
|
-
type: "button",
|
|
330
|
-
class: "mint-experiment-popover__detach-btn",
|
|
331
|
-
onClick: handleDetach
|
|
332
|
-
}, " Detach ")) : createCommentVNode("", true)])]))])) : createCommentVNode("", true),
|
|
333
|
-
createVNode(ConfirmDialog_default, {
|
|
334
|
-
open: showConfirm.value,
|
|
335
|
-
"onUpdate:open": _cache[0] || (_cache[0] = ($event) => showConfirm.value = $event),
|
|
336
|
-
title: __props.confirmTitle ?? "Save to Experiment",
|
|
337
|
-
message: __props.confirmMessage ?? `Save current data to ${__props.experimentName}?`,
|
|
338
|
-
tone: "info",
|
|
339
|
-
"confirm-label": "Save",
|
|
340
|
-
loading: __props.saveLoading,
|
|
341
|
-
onConfirm: handleConfirmSave
|
|
342
|
-
}, null, 8, [
|
|
343
|
-
"open",
|
|
344
|
-
"title",
|
|
345
|
-
"message",
|
|
346
|
-
"loading"
|
|
347
|
-
])
|
|
348
|
-
], 512);
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
//#endregion
|
|
353
|
-
//#region src/components/ExperimentPopover.vue
|
|
354
|
-
var ExperimentPopover_exports = /* @__PURE__ */ __exportAll({ default: () => ExperimentPopover_default });
|
|
355
|
-
var ExperimentPopover_default = ExperimentPopover_vue_vue_type_script_setup_true_lang_default;
|
|
356
|
-
//#endregion
|
|
357
|
-
export { ExperimentPopover_exports as n, ExperimentPopover_default as t };
|
|
358
|
-
|
|
359
|
-
//# sourceMappingURL=ExperimentPopover-C4sGw-is.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ExperimentPopover-C4sGw-is.js","names":[],"sources":["../src/components/ExperimentPopover.vue","../src/components/ExperimentPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Floating popover showing the active experiment with save, detach, and select actions. */\nimport { ref, computed, watch, onUnmounted, useTemplateRef } from 'vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { format as formatStatus } from '../utils/experimentStatus'\nimport ConfirmDialog from './ConfirmDialog.vue'\n\ninterface Props {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: string\n /** An experiment is bound but the platform has not returned its record yet. */\n isResolving?: boolean\n /** Message explaining why the bound experiment could not be resolved. */\n error?: string\n showSave?: boolean\n showDetach?: boolean\n saveDisabled?: boolean\n saveLoading?: boolean\n saveSuccessMessage?: string\n saveDisabledMessage?: string\n confirmSave?: boolean\n confirmTitle?: string\n confirmMessage?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isResolving: false,\n showSave: false,\n showDetach: false,\n saveDisabled: false,\n saveLoading: false,\n confirmSave: true,\n})\n\n// An experiment is bound but has no name to show — either still resolving or\n// resolution failed. The id is never substituted: a name may only come from the\n// platform, so these states say what is happening instead of inventing a label.\nconst isUnresolved = computed(() => props.isResolving || !!props.error)\nconst hasExperiment = computed(() => !!props.experimentName || !!props.experimentCode)\n\nconst panelSubtitle = computed(() => {\n if (props.isResolving) return 'Loading experiment…'\n if (props.error) return 'Could not load this experiment'\n return hasExperiment.value ? 'Linked experiment context' : 'Link to an MINT experiment'\n})\n\nconst triggerLabel = computed(() => {\n if (props.isResolving) return 'Loading experiment'\n if (props.error) return 'Experiment unavailable'\n return props.experimentName || props.experimentCode || 'No experiment'\n})\n\nconst emit = defineEmits<{\n select: []\n save: []\n detach: []\n}>()\n\nconst { isOpen, close, toggle } = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('popover'),\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\nconst showSuccess = ref(false)\nconst showConfirm = ref(false)\n\nfunction handleTriggerClick() {\n if (!hasExperiment.value && !isUnresolved.value) {\n handleSelect()\n return\n }\n toggle()\n}\n\nfunction handleSelect() {\n emit('select')\n close()\n}\n\nfunction handleSave() {\n if (props.saveDisabled || props.saveLoading) return\n if (props.confirmSave) {\n showConfirm.value = true\n } else {\n emit('save')\n }\n}\n\nfunction handleConfirmSave() {\n showConfirm.value = false\n emit('save')\n}\n\nfunction handleDetach() {\n emit('detach')\n close()\n}\n\nlet successTimer: ReturnType<typeof setTimeout> | null = null\n\n// Show success state when saveSuccessMessage changes from empty to a value\nwatch(() => props.saveSuccessMessage, (msg) => {\n if (successTimer) clearTimeout(successTimer)\n if (msg) {\n showSuccess.value = true\n successTimer = setTimeout(() => {\n showSuccess.value = false\n successTimer = null\n }, 3000)\n }\n})\n\nonUnmounted(() => {\n if (successTimer) clearTimeout(successTimer)\n})\n</script>\n\n<template>\n <div ref=\"popover\" class=\"mint-experiment-popover\">\n <!-- Split trigger: experiment pill + inline save -->\n <div\n :class=\"[\n 'mint-experiment-popover__split',\n { 'mint-experiment-popover__split--with-save': showSave && experimentName },\n ]\"\n >\n <!-- Left: experiment trigger (selects when empty, otherwise opens popover). Prefer the human-readable\n name; the formal code, when present, stays in the detail panel. -->\n <button\n ref=\"trigger\"\n type=\"button\"\n :class=\"[\n 'mint-experiment-popover__trigger',\n { 'mint-experiment-popover__trigger--active': isOpen },\n { 'mint-experiment-popover__trigger--empty': !isUnresolved && !hasExperiment },\n { 'mint-experiment-popover__trigger--loading': isResolving },\n { 'mint-experiment-popover__trigger--error': !isResolving && !!error },\n ]\"\n :title=\"isUnresolved ? triggerLabel : experimentName || experimentCode || undefined\"\n :aria-label=\"isUnresolved ? triggerLabel : undefined\"\n :aria-busy=\"isResolving || undefined\"\n :aria-expanded=\"isOpen\"\n @click.stop=\"handleTriggerClick\"\n >\n <!-- Flask icon -->\n <svg class=\"mint-experiment-popover__trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n <!-- Resolving and error come first: with an experiment bound but no name\n yet, \"No experiment\" would be a lie. -->\n <span v-if=\"isResolving\" class=\"mint-experiment-popover__trigger-skeleton\" aria-hidden=\"true\" />\n <span v-else-if=\"error\" class=\"mint-experiment-popover__trigger-text\">Experiment unavailable</span>\n <!-- Name preferred, code as fallback, \"No experiment\" as empty state -->\n <span v-else-if=\"experimentName\" class=\"mint-experiment-popover__trigger-text\">{{ experimentName }}</span>\n <span v-else-if=\"experimentCode\" class=\"mint-experiment-popover__trigger-code\">{{ experimentCode }}</span>\n <span v-else class=\"mint-experiment-popover__trigger-text\">No experiment</span>\n <!-- Chevron -->\n <svg class=\"mint-experiment-popover__trigger-chevron\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Right: inline save button (direct action) -->\n <button\n v-if=\"showSave && experimentName\"\n type=\"button\"\n :class=\"[\n 'mint-experiment-popover__save-trigger',\n { 'mint-experiment-popover__save-trigger--loading': saveLoading },\n { 'mint-experiment-popover__save-trigger--success': showSuccess },\n { 'mint-experiment-popover__save-trigger--disabled': saveDisabled && !showSuccess },\n ]\"\n :disabled=\"saveDisabled && !showSuccess\"\n :title=\"saveDisabled && saveDisabledMessage ? saveDisabledMessage : showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment'\"\n aria-label=\"Save to experiment\"\n @click.stop=\"handleSave\"\n >\n <!-- Loading spinner -->\n <span v-if=\"saveLoading\" class=\"mint-experiment-popover__spinner--inline\" />\n <!-- Success check -->\n <svg v-else-if=\"showSuccess\" class=\"mint-experiment-popover__save-trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.5\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <!-- Save icon -->\n <svg v-else class=\"mint-experiment-popover__save-trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4\" />\n </svg>\n </button>\n </div>\n\n <!-- Popover panel -->\n <div v-if=\"isOpen\" class=\"mint-experiment-popover__panel\">\n <!-- Header -->\n <div class=\"mint-experiment-popover__header\">\n <div class=\"mint-experiment-popover__title\">Experiment</div>\n <div class=\"mint-experiment-popover__subtitle\">\n {{ panelSubtitle }}\n </div>\n </div>\n\n <!-- Bound, still resolving — placeholders stand in for the record the\n platform has not returned yet. -->\n <div v-if=\"isResolving\" class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card\" aria-busy=\"true\">\n <div class=\"mint-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--code\" />\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--name\" />\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--status\" />\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n\n <!-- Bound, resolution failed — Detach stays reachable so the user is not\n stuck on an experiment the platform cannot describe. -->\n <div v-else-if=\"error\" class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card mint-experiment-popover__card--error\" role=\"alert\">\n <div class=\"mint-experiment-popover__card-icon mint-experiment-popover__card-icon--error\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <div class=\"mint-experiment-popover__card-name\">Experiment unavailable</div>\n <div class=\"mint-experiment-popover__card-message\">{{ error }}</div>\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n\n <!-- No experiment selected -->\n <div v-else-if=\"!experimentName\" class=\"mint-experiment-popover__body\">\n <button type=\"button\" class=\"mint-experiment-popover__select-btn\" @click=\"handleSelect\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n Select Experiment\n </button>\n </div>\n\n <!-- Experiment selected -->\n <div v-else class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card\">\n <div class=\"mint-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <span v-if=\"experimentCode\" class=\"mint-experiment-popover__card-code\">{{ experimentCode }}</span>\n <div class=\"mint-experiment-popover__card-name\">{{ experimentName }}</div>\n <div v-if=\"experimentStatus\" class=\"mint-experiment-popover__card-status\">\n {{ formatStatus(experimentStatus) }}\n </div>\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n </div>\n\n <!-- Save confirmation dialog -->\n <ConfirmDialog\n v-model:open=\"showConfirm\"\n :title=\"confirmTitle ?? 'Save to Experiment'\"\n :message=\"confirmMessage ?? `Save current data to ${experimentName}?`\"\n tone=\"info\"\n confirm-label=\"Save\"\n :loading=\"saveLoading\"\n @confirm=\"handleConfirmSave\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Floating popover showing the active experiment with save, detach, and select actions. */\nimport { ref, computed, watch, onUnmounted, useTemplateRef } from 'vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { format as formatStatus } from '../utils/experimentStatus'\nimport ConfirmDialog from './ConfirmDialog.vue'\n\ninterface Props {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: string\n /** An experiment is bound but the platform has not returned its record yet. */\n isResolving?: boolean\n /** Message explaining why the bound experiment could not be resolved. */\n error?: string\n showSave?: boolean\n showDetach?: boolean\n saveDisabled?: boolean\n saveLoading?: boolean\n saveSuccessMessage?: string\n saveDisabledMessage?: string\n confirmSave?: boolean\n confirmTitle?: string\n confirmMessage?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isResolving: false,\n showSave: false,\n showDetach: false,\n saveDisabled: false,\n saveLoading: false,\n confirmSave: true,\n})\n\n// An experiment is bound but has no name to show — either still resolving or\n// resolution failed. The id is never substituted: a name may only come from the\n// platform, so these states say what is happening instead of inventing a label.\nconst isUnresolved = computed(() => props.isResolving || !!props.error)\nconst hasExperiment = computed(() => !!props.experimentName || !!props.experimentCode)\n\nconst panelSubtitle = computed(() => {\n if (props.isResolving) return 'Loading experiment…'\n if (props.error) return 'Could not load this experiment'\n return hasExperiment.value ? 'Linked experiment context' : 'Link to an MINT experiment'\n})\n\nconst triggerLabel = computed(() => {\n if (props.isResolving) return 'Loading experiment'\n if (props.error) return 'Experiment unavailable'\n return props.experimentName || props.experimentCode || 'No experiment'\n})\n\nconst emit = defineEmits<{\n select: []\n save: []\n detach: []\n}>()\n\nconst { isOpen, close, toggle } = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('popover'),\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\nconst showSuccess = ref(false)\nconst showConfirm = ref(false)\n\nfunction handleTriggerClick() {\n if (!hasExperiment.value && !isUnresolved.value) {\n handleSelect()\n return\n }\n toggle()\n}\n\nfunction handleSelect() {\n emit('select')\n close()\n}\n\nfunction handleSave() {\n if (props.saveDisabled || props.saveLoading) return\n if (props.confirmSave) {\n showConfirm.value = true\n } else {\n emit('save')\n }\n}\n\nfunction handleConfirmSave() {\n showConfirm.value = false\n emit('save')\n}\n\nfunction handleDetach() {\n emit('detach')\n close()\n}\n\nlet successTimer: ReturnType<typeof setTimeout> | null = null\n\n// Show success state when saveSuccessMessage changes from empty to a value\nwatch(() => props.saveSuccessMessage, (msg) => {\n if (successTimer) clearTimeout(successTimer)\n if (msg) {\n showSuccess.value = true\n successTimer = setTimeout(() => {\n showSuccess.value = false\n successTimer = null\n }, 3000)\n }\n})\n\nonUnmounted(() => {\n if (successTimer) clearTimeout(successTimer)\n})\n</script>\n\n<template>\n <div ref=\"popover\" class=\"mint-experiment-popover\">\n <!-- Split trigger: experiment pill + inline save -->\n <div\n :class=\"[\n 'mint-experiment-popover__split',\n { 'mint-experiment-popover__split--with-save': showSave && experimentName },\n ]\"\n >\n <!-- Left: experiment trigger (selects when empty, otherwise opens popover). Prefer the human-readable\n name; the formal code, when present, stays in the detail panel. -->\n <button\n ref=\"trigger\"\n type=\"button\"\n :class=\"[\n 'mint-experiment-popover__trigger',\n { 'mint-experiment-popover__trigger--active': isOpen },\n { 'mint-experiment-popover__trigger--empty': !isUnresolved && !hasExperiment },\n { 'mint-experiment-popover__trigger--loading': isResolving },\n { 'mint-experiment-popover__trigger--error': !isResolving && !!error },\n ]\"\n :title=\"isUnresolved ? triggerLabel : experimentName || experimentCode || undefined\"\n :aria-label=\"isUnresolved ? triggerLabel : undefined\"\n :aria-busy=\"isResolving || undefined\"\n :aria-expanded=\"isOpen\"\n @click.stop=\"handleTriggerClick\"\n >\n <!-- Flask icon -->\n <svg class=\"mint-experiment-popover__trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n <!-- Resolving and error come first: with an experiment bound but no name\n yet, \"No experiment\" would be a lie. -->\n <span v-if=\"isResolving\" class=\"mint-experiment-popover__trigger-skeleton\" aria-hidden=\"true\" />\n <span v-else-if=\"error\" class=\"mint-experiment-popover__trigger-text\">Experiment unavailable</span>\n <!-- Name preferred, code as fallback, \"No experiment\" as empty state -->\n <span v-else-if=\"experimentName\" class=\"mint-experiment-popover__trigger-text\">{{ experimentName }}</span>\n <span v-else-if=\"experimentCode\" class=\"mint-experiment-popover__trigger-code\">{{ experimentCode }}</span>\n <span v-else class=\"mint-experiment-popover__trigger-text\">No experiment</span>\n <!-- Chevron -->\n <svg class=\"mint-experiment-popover__trigger-chevron\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Right: inline save button (direct action) -->\n <button\n v-if=\"showSave && experimentName\"\n type=\"button\"\n :class=\"[\n 'mint-experiment-popover__save-trigger',\n { 'mint-experiment-popover__save-trigger--loading': saveLoading },\n { 'mint-experiment-popover__save-trigger--success': showSuccess },\n { 'mint-experiment-popover__save-trigger--disabled': saveDisabled && !showSuccess },\n ]\"\n :disabled=\"saveDisabled && !showSuccess\"\n :title=\"saveDisabled && saveDisabledMessage ? saveDisabledMessage : showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment'\"\n aria-label=\"Save to experiment\"\n @click.stop=\"handleSave\"\n >\n <!-- Loading spinner -->\n <span v-if=\"saveLoading\" class=\"mint-experiment-popover__spinner--inline\" />\n <!-- Success check -->\n <svg v-else-if=\"showSuccess\" class=\"mint-experiment-popover__save-trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.5\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <!-- Save icon -->\n <svg v-else class=\"mint-experiment-popover__save-trigger-icon\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4\" />\n </svg>\n </button>\n </div>\n\n <!-- Popover panel -->\n <div v-if=\"isOpen\" class=\"mint-experiment-popover__panel\">\n <!-- Header -->\n <div class=\"mint-experiment-popover__header\">\n <div class=\"mint-experiment-popover__title\">Experiment</div>\n <div class=\"mint-experiment-popover__subtitle\">\n {{ panelSubtitle }}\n </div>\n </div>\n\n <!-- Bound, still resolving — placeholders stand in for the record the\n platform has not returned yet. -->\n <div v-if=\"isResolving\" class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card\" aria-busy=\"true\">\n <div class=\"mint-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--code\" />\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--name\" />\n <span class=\"mint-experiment-popover__skeleton-line mint-experiment-popover__skeleton-line--status\" />\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n\n <!-- Bound, resolution failed — Detach stays reachable so the user is not\n stuck on an experiment the platform cannot describe. -->\n <div v-else-if=\"error\" class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card mint-experiment-popover__card--error\" role=\"alert\">\n <div class=\"mint-experiment-popover__card-icon mint-experiment-popover__card-icon--error\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <div class=\"mint-experiment-popover__card-name\">Experiment unavailable</div>\n <div class=\"mint-experiment-popover__card-message\">{{ error }}</div>\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n\n <!-- No experiment selected -->\n <div v-else-if=\"!experimentName\" class=\"mint-experiment-popover__body\">\n <button type=\"button\" class=\"mint-experiment-popover__select-btn\" @click=\"handleSelect\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n Select Experiment\n </button>\n </div>\n\n <!-- Experiment selected -->\n <div v-else class=\"mint-experiment-popover__body\">\n <div class=\"mint-experiment-popover__card\">\n <div class=\"mint-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n </div>\n <div class=\"mint-experiment-popover__card-info\">\n <span v-if=\"experimentCode\" class=\"mint-experiment-popover__card-code\">{{ experimentCode }}</span>\n <div class=\"mint-experiment-popover__card-name\">{{ experimentName }}</div>\n <div v-if=\"experimentStatus\" class=\"mint-experiment-popover__card-status\">\n {{ formatStatus(experimentStatus) }}\n </div>\n </div>\n </div>\n <div class=\"mint-experiment-popover__card-actions\">\n <button type=\"button\" class=\"mint-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n <button v-if=\"showDetach\" type=\"button\" class=\"mint-experiment-popover__detach-btn\" @click=\"handleDetach\">\n Detach\n </button>\n </div>\n </div>\n </div>\n\n <!-- Save confirmation dialog -->\n <ConfirmDialog\n v-model:open=\"showConfirm\"\n :title=\"confirmTitle ?? 'Save to Experiment'\"\n :message=\"confirmMessage ?? `Save current data to ${experimentName}?`\"\n tone=\"info\"\n confirm-label=\"Save\"\n :loading=\"saveLoading\"\n @confirm=\"handleConfirmSave\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|