@morscherlab/mint-sdk 1.4.0-beta.12 → 1.4.0-beta.13

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.
Files changed (43) hide show
  1. package/dist/{AppSidebar-DGK5i-hJ.js → AppSidebar-CIXJBzDv.js} +234 -67
  2. package/dist/{AppSidebar-DGK5i-hJ.js.map → AppSidebar-CIXJBzDv.js.map} +1 -1
  3. package/dist/{ExperimentSelectorModal-BoofZZxF.js → ExperimentSelectorModal-BbFtr1Fr.js} +109 -93
  4. package/dist/ExperimentSelectorModal-BbFtr1Fr.js.map +1 -0
  5. package/dist/{SettingsModal-BXsjIVnm.js → SettingsModal-CdhFMi8j.js} +2 -2
  6. package/dist/{SettingsModal-BXsjIVnm.js.map → SettingsModal-CdhFMi8j.js.map} +1 -1
  7. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  8. package/dist/components/AppTopBar.vue.d.ts +13 -5
  9. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -1
  10. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  11. package/dist/{data-ihsBd9bs.js → data-DUt0TIp5.js} +2 -2
  12. package/dist/{data-ihsBd9bs.js.map → data-DUt0TIp5.js.map} +1 -1
  13. package/dist/data.js +2 -2
  14. package/dist/index.js +7 -7
  15. package/dist/{install-CFgfRO64.js → install-Czoe1rA8.js} +6 -6
  16. package/dist/{install-CFgfRO64.js.map → install-Czoe1rA8.js.map} +1 -1
  17. package/dist/install.js +1 -1
  18. package/dist/{runtime-pKfF_iql.js → runtime-fPb_FEZr.js} +2 -2
  19. package/dist/{runtime-pKfF_iql.js.map → runtime-fPb_FEZr.js.map} +1 -1
  20. package/dist/runtime.js +2 -2
  21. package/dist/{shell-BIH8Rc21.js → shell-lDf_EY-x.js} +2 -2
  22. package/dist/{shell-BIH8Rc21.js.map → shell-lDf_EY-x.js.map} +1 -1
  23. package/dist/shell.js +2 -2
  24. package/dist/styles.css +288 -45
  25. package/dist/types/index.d.ts +1 -1
  26. package/dist/types/jobs.d.ts +9 -0
  27. package/package.json +1 -1
  28. package/src/__stories__/experiment-helpers.ts +3 -3
  29. package/src/__tests__/components/AppTopBar.test.ts +175 -1
  30. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  31. package/src/__tests__/components/ExperimentSelectorModal.test.ts +34 -1
  32. package/src/__tests__/styles/menusShellRefresh.test.ts +8 -2
  33. package/src/components/AppTopBar.story.vue +59 -4
  34. package/src/components/AppTopBar.vue +107 -8
  35. package/src/components/ExperimentSelectorModal.story.vue +38 -0
  36. package/src/components/ExperimentSelectorModal.vue +20 -1
  37. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  38. package/src/styles/components/app-page-selector.css +120 -45
  39. package/src/styles/components/app-top-bar.css +155 -0
  40. package/src/styles/components/experiment-selector-modal.css +13 -0
  41. package/src/types/index.ts +1 -0
  42. package/src/types/jobs.ts +10 -0
  43. package/dist/ExperimentSelectorModal-BoofZZxF.js.map +0 -1
package/dist/runtime.js CHANGED
@@ -2,7 +2,7 @@ import { i as AuthenticationRequiredError, o as useApi } from "./experiment-DyO5
2
2
  import { c as isTerminalJobStatus, d as normalizeJobState, f as resolveJobCapabilities, l as jobStatusLabel, o as resolveCurrentPluginId, s as isActiveJobStatus, u as normalizeJobPercent } from "./records-DnK_1Q_S.js";
3
3
  import { A as createGeneratedAnalysisTransport, D as GeneratedPathInput_default, _ as getFieldRegistryEntry, j as useJobsEndpoint, v as getTypeDefault } from "./useListReorder-DPynGrCj.js";
4
4
  import { a as GeneratedPlotlyResult_default, c as downloadEndpoint, d as useEventStream, f as useSettingsEndpoint, i as GeneratedResultRenderer_default, l as pluginFormDataFromPayload, m as resolvePluginBaseUrl, o as createClient, p as buildEndpointUrl, u as uploadEndpoint } from "./useRackEditor-B2FrQA0p.js";
5
- import { a as ComponentBindingRenderer_default, c as generatedJobFormSchema, f as useControlWorkspace, i as RuntimeUpdateNotice_default, l as normalizeGeneratedJobInput, n as PresenceAvatars_default, o as GeneratedPluginView_default, r as usePresence, s as generatedJobDefaults } from "./runtime-pKfF_iql.js";
6
- import { A as getDefaultControlView, C as controlBindings, D as controlsTo, S as useControlSchema, b as defineControls, d as useForm, l as useFormBuilder, u as evaluateCondition, x as getControlDefaults, y as defineControlComponentBindings } from "./AppSidebar-DGK5i-hJ.js";
5
+ import { a as ComponentBindingRenderer_default, c as generatedJobFormSchema, f as useControlWorkspace, i as RuntimeUpdateNotice_default, l as normalizeGeneratedJobInput, n as PresenceAvatars_default, o as GeneratedPluginView_default, r as usePresence, s as generatedJobDefaults } from "./runtime-fPb_FEZr.js";
6
+ import { A as getDefaultControlView, C as controlBindings, D as controlsTo, S as useControlSchema, b as defineControls, d as useForm, l as useFormBuilder, u as evaluateCondition, x as getControlDefaults, y as defineControlComponentBindings } from "./AppSidebar-CIXJBzDv.js";
7
7
  import { a as combinePluginJobSources, o as useJobCenter, r as useRealtime } from "./useRealtime-yWjTTnc9.js";
8
8
  export { AuthenticationRequiredError, ComponentBindingRenderer_default as ComponentBindingRenderer, GeneratedPathInput_default as GeneratedPathInput, GeneratedPlotlyResult_default as GeneratedPlotlyResult, GeneratedPluginView_default as GeneratedPluginView, GeneratedResultRenderer_default as GeneratedResultRenderer, PresenceAvatars_default as PresenceAvatars, RuntimeUpdateNotice_default as RuntimeUpdateNotice, buildEndpointUrl, combinePluginJobSources, controlBindings, controlsTo, createClient, createGeneratedAnalysisTransport, defineControlComponentBindings, defineControls, downloadEndpoint, evaluateCondition, generatedJobDefaults, generatedJobFormSchema, getControlDefaults, getDefaultControlView, getFieldRegistryEntry, getTypeDefault, isActiveJobStatus, isTerminalJobStatus, jobStatusLabel, normalizeGeneratedJobInput, normalizeJobPercent, normalizeJobState, pluginFormDataFromPayload, resolveCurrentPluginId, resolveJobCapabilities, resolvePluginBaseUrl, uploadEndpoint, useApi, useControlSchema, useControlWorkspace, useEventStream, useForm, useFormBuilder, useJobCenter, useJobsEndpoint, usePresence, useRealtime, useSettingsEndpoint };
@@ -1,7 +1,7 @@
1
1
  import { i as useEventListener, o as __exportAll, r as useFocusTrap } from "./useDropdownState-8yWMu-7_.js";
2
2
  import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-DnK_1Q_S.js";
3
3
  import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-DPynGrCj.js";
4
- import { _ as AppLayout_default, f as AppTopBar_default, t as AppSidebar_default, v as usePluginWorkspace } from "./AppSidebar-DGK5i-hJ.js";
4
+ import { _ as AppLayout_default, f as AppTopBar_default, t as AppSidebar_default, v as usePluginWorkspace } from "./AppSidebar-CIXJBzDv.js";
5
5
  import { t as useDebouncedWatch } from "./useDebouncedWatch-BPwyl6eS.js";
6
6
  import { t as useExpansionSet } from "./useExpansionSet-CvoNMZJi.js";
7
7
  import { computed, createElementBlock, createElementVNode, defineComponent, normalizeClass, onBeforeUnmount, openBlock, shallowRef, toValue, watch } from "vue";
@@ -194,4 +194,4 @@ var shell_exports = /* @__PURE__ */ __exportAll({
194
194
  //#endregion
195
195
  export { useManualLayoutResize as a, resizedVerticalSplitPercent as i, resizedLeadingPanelWidth as n, LayoutResizeHandle_default as o, resizedTrailingPanelWidth as r, shell_exports as t };
196
196
 
197
- //# sourceMappingURL=shell-BIH8Rc21.js.map
197
+ //# sourceMappingURL=shell-lDf_EY-x.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-BIH8Rc21.js","names":[],"sources":["../src/components/LayoutResizeHandle.vue","../src/components/LayoutResizeHandle.vue","../src/composables/useManualLayoutResize.ts","../src/shell.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/** Accessible pointer and keyboard handle for resizable workbench panes. */\ninterface Props {\n modelValue: number\n min: number\n max: number\n label: string\n orientation: 'vertical' | 'horizontal'\n edge?: 'left' | 'right'\n step?: number\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n edge: undefined,\n step: 10,\n disabled: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number]\n 'resize-start': [event: PointerEvent]\n}>()\n\nfunction update(value: number): void {\n emit('update:modelValue', Math.min(props.max, Math.max(props.min, value)))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (props.disabled) return\n const decrement = props.orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp'\n const increment = props.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown'\n if (event.key === decrement) update(props.modelValue - props.step)\n else if (event.key === increment) update(props.modelValue + props.step)\n else if (event.key === 'Home') update(props.min)\n else if (event.key === 'End') update(props.max)\n else return\n event.preventDefault()\n}\n</script>\n\n<template>\n <div\n role=\"separator\"\n :tabindex=\"disabled ? -1 : 0\"\n :class=\"[\n 'mint-layout-resize-handle',\n `mint-layout-resize-handle--${orientation}`,\n edge ? `mint-layout-resize-handle--edge-${edge}` : '',\n ]\"\n :aria-label=\"label\"\n :aria-orientation=\"orientation\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-valuenow=\"modelValue\"\n :aria-disabled=\"disabled || undefined\"\n @pointerdown=\"!disabled && emit('resize-start', $event)\"\n @keydown=\"handleKeydown\"\n >\n <span class=\"mint-layout-resize-handle__bar\" aria-hidden=\"true\" />\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Accessible pointer and keyboard handle for resizable workbench panes. */\ninterface Props {\n modelValue: number\n min: number\n max: number\n label: string\n orientation: 'vertical' | 'horizontal'\n edge?: 'left' | 'right'\n step?: number\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n edge: undefined,\n step: 10,\n disabled: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number]\n 'resize-start': [event: PointerEvent]\n}>()\n\nfunction update(value: number): void {\n emit('update:modelValue', Math.min(props.max, Math.max(props.min, value)))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (props.disabled) return\n const decrement = props.orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp'\n const increment = props.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown'\n if (event.key === decrement) update(props.modelValue - props.step)\n else if (event.key === increment) update(props.modelValue + props.step)\n else if (event.key === 'Home') update(props.min)\n else if (event.key === 'End') update(props.max)\n else return\n event.preventDefault()\n}\n</script>\n\n<template>\n <div\n role=\"separator\"\n :tabindex=\"disabled ? -1 : 0\"\n :class=\"[\n 'mint-layout-resize-handle',\n `mint-layout-resize-handle--${orientation}`,\n edge ? `mint-layout-resize-handle--edge-${edge}` : '',\n ]\"\n :aria-label=\"label\"\n :aria-orientation=\"orientation\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-valuenow=\"modelValue\"\n :aria-disabled=\"disabled || undefined\"\n @pointerdown=\"!disabled && emit('resize-start', $event)\"\n @keydown=\"handleKeydown\"\n >\n <span class=\"mint-layout-resize-handle__bar\" aria-hidden=\"true\" />\n </div>\n</template>\n","import { computed, onBeforeUnmount, shallowRef, toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nexport interface ResizePanelWidthConstraints {\n minWidth: number\n maxWidth: number\n mainMinWidth?: number\n layoutGap?: number\n}\n\nexport interface ResizePercentConstraints {\n minPercent: number\n maxPercent: number\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n\nfunction availablePanelWidth(\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return Math.min(\n constraints.maxWidth,\n containerWidth - (constraints.mainMinWidth ?? 0) - (constraints.layoutGap ?? 0),\n )\n}\n\nexport function resizedLeadingPanelWidth(\n startWidth: number,\n deltaX: number,\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return Math.round(clamp(\n startWidth + deltaX,\n constraints.minWidth,\n Math.max(constraints.minWidth, availablePanelWidth(containerWidth, constraints)),\n ))\n}\n\nexport function resizedTrailingPanelWidth(\n startWidth: number,\n deltaX: number,\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return resizedLeadingPanelWidth(startWidth, -deltaX, containerWidth, constraints)\n}\n\nexport function resizedVerticalSplitPercent(\n startPercent: number,\n deltaY: number,\n containerHeight: number,\n constraints: ResizePercentConstraints,\n): number {\n if (containerHeight <= 0) return startPercent\n return Math.round(clamp(\n startPercent + (deltaY / containerHeight) * 100,\n constraints.minPercent,\n constraints.maxPercent,\n ))\n}\n\nexport interface ManualLayoutResizeContext<TKind extends string> {\n kind: TKind\n startValue: number\n deltaX: number\n deltaY: number\n containerRect: DOMRectReadOnly\n secondaryRect: DOMRectReadOnly | null\n}\n\nexport interface ManualLayoutResizeTarget<TKind extends string> {\n cursor?: string\n getContainerElement: () => HTMLElement | null\n getSecondaryElement?: () => HTMLElement | null\n getStartValue: () => number\n onResize: (context: ManualLayoutResizeContext<TKind>) => void\n}\n\n/** Coordinates pointer-driven resizing for one or more layout splitters. */\nexport function useManualLayoutResize<TKind extends string>(options: {\n enabled: MaybeRefOrGetter<boolean>\n resolveTarget: (kind: TKind) => ManualLayoutResizeTarget<TKind> | null\n}) {\n const activeResize = shallowRef<{\n kind: TKind\n startClientX: number\n startClientY: number\n startValue: number\n containerRect: DOMRectReadOnly\n secondaryRect: DOMRectReadOnly | null\n cursor: string\n } | null>(null)\n const isResizing = computed(() => activeResize.value !== null)\n let previousBodyCursor = ''\n let previousBodyUserSelect = ''\n\n function stopResize(): void {\n if (!activeResize.value) return\n activeResize.value = null\n window.removeEventListener('pointermove', handlePointerMove)\n window.removeEventListener('pointerup', stopResize)\n window.removeEventListener('pointercancel', stopResize)\n if (typeof document !== 'undefined') {\n document.body.style.cursor = previousBodyCursor\n document.body.style.userSelect = previousBodyUserSelect\n }\n }\n\n function handlePointerMove(event: PointerEvent): void {\n const state = activeResize.value\n if (!state) return\n options.resolveTarget(state.kind)?.onResize({\n kind: state.kind,\n startValue: state.startValue,\n deltaX: event.clientX - state.startClientX,\n deltaY: event.clientY - state.startClientY,\n containerRect: state.containerRect,\n secondaryRect: state.secondaryRect,\n })\n }\n\n function startResize(kind: TKind, event: PointerEvent): void {\n if (!toValue(options.enabled) || event.button !== 0) return\n const target = options.resolveTarget(kind)\n const containerRect = target?.getContainerElement()?.getBoundingClientRect()\n if (!target || !containerRect) return\n\n event.preventDefault()\n if (event.currentTarget instanceof HTMLElement) {\n event.currentTarget.setPointerCapture(event.pointerId)\n }\n const secondary = target.getSecondaryElement?.() ?? null\n activeResize.value = {\n kind,\n startClientX: event.clientX,\n startClientY: event.clientY,\n startValue: target.getStartValue(),\n containerRect,\n secondaryRect: secondary?.getBoundingClientRect() ?? null,\n cursor: target.cursor ?? 'col-resize',\n }\n\n if (typeof document !== 'undefined') {\n previousBodyCursor = document.body.style.cursor\n previousBodyUserSelect = document.body.style.userSelect\n document.body.style.cursor = activeResize.value.cursor\n document.body.style.userSelect = 'none'\n }\n window.addEventListener('pointermove', handlePointerMove)\n window.addEventListener('pointerup', stopResize)\n window.addEventListener('pointercancel', stopResize)\n }\n\n function isResizingKind(kind: TKind): boolean {\n return activeResize.value?.kind === kind\n }\n\n watch(() => toValue(options.enabled), enabled => { if (!enabled) stopResize() })\n onBeforeUnmount(stopResize)\n\n return { activeResize, isResizing, isResizingKind, startResize, stopResize }\n}\n","// Application shell components (`@morscherlab/mint-sdk/shell`).\n\n// Layout components\nexport { default as AppTopBar } from './components/AppTopBar.vue'\nexport { default as AppSidebar } from './components/AppSidebar.vue'\nexport { default as AppLayout } from './components/AppLayout.vue'\nexport { default as LayoutResizeHandle } from './components/LayoutResizeHandle.vue'\n\n// Headless interaction composables\nexport {\n useEventListener,\n type EventListenerEnabled,\n type EventFor,\n type EventListenerStop,\n type EventMapFor,\n type EventTargetGetter,\n type EventTargetLike,\n type UseEventListenerObjectOptions,\n type UseEventListenerOptions,\n} from './composables/useEventListener'\nexport {\n useDebouncedWatch,\n type DebouncedWatchCallback,\n type DebouncedWatchCleanup,\n type DebouncedWatchSource,\n type UseDebouncedWatchOptions,\n type UseDebouncedWatchReturn,\n} from './composables/useDebouncedWatch'\nexport {\n useFocusTrap,\n type UseFocusTrapOptions,\n type UseFocusTrapReturn,\n} from './composables/useFocusTrap'\nexport {\n useRovingFocus,\n type UseRovingFocusOptions,\n type UseRovingFocusReturn,\n} from './composables/useRovingFocus'\nexport {\n reorderList,\n useListReorder,\n useReorderAnnouncer,\n REORDER_ANNOUNCER_STYLE,\n type ListReorderMove,\n type UseListReorderOptions,\n type UseListReorderReturn,\n type UseReorderAnnouncerReturn,\n} from './composables/useListReorder'\nexport {\n useMenuKeyboard,\n type UseMenuKeyboardOptions,\n type UseMenuKeyboardReturn,\n} from './composables/useMenuKeyboard'\n\n// Layout, selection, expansion and sort primitives\nexport {\n resizedLeadingPanelWidth,\n resizedTrailingPanelWidth,\n resizedVerticalSplitPercent,\n useManualLayoutResize,\n type ManualLayoutResizeContext,\n type ManualLayoutResizeTarget,\n type ResizePanelWidthConstraints,\n type ResizePercentConstraints,\n} from './composables/useManualLayoutResize'\nexport {\n useSelectionLimit,\n type SelectionLimitSource,\n type UseSelectionLimitOptions,\n type UseSelectionLimitReturn,\n} from './composables/useSelectionLimit'\nexport {\n useListSelection,\n type ListSelectionSource,\n type ListSelectionValue,\n type UseListSelectionOptions,\n type UseListSelectionReturn,\n type WidenListSelectionValue,\n} from './composables/useListSelection'\nexport {\n useExpansionSet,\n type ExpansionSetSource,\n type UseExpansionSetOptions,\n type UseExpansionSetReturn,\n} from './composables/useExpansionSet'\nexport {\n compareSortValues,\n useSortedItems,\n type CompareSortValuesOptions,\n type SortComparator,\n type SortComparatorContext,\n type SortDescriptor,\n type SortedItemsSource,\n type SortOrder,\n type UseSortedItemsOptions,\n type UseSortedItemsReturn,\n} from './composables/useSortedItems'\nexport {\n usePluginWorkspace,\n type PluginWorkspaceSlotsLike,\n type UsePluginWorkspaceOptions,\n type UsePluginWorkspaceReturn,\n} from './composables/usePluginWorkspace'\n"],"mappings":"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"}
1
+ {"version":3,"file":"shell-lDf_EY-x.js","names":[],"sources":["../src/components/LayoutResizeHandle.vue","../src/components/LayoutResizeHandle.vue","../src/composables/useManualLayoutResize.ts","../src/shell.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/** Accessible pointer and keyboard handle for resizable workbench panes. */\ninterface Props {\n modelValue: number\n min: number\n max: number\n label: string\n orientation: 'vertical' | 'horizontal'\n edge?: 'left' | 'right'\n step?: number\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n edge: undefined,\n step: 10,\n disabled: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number]\n 'resize-start': [event: PointerEvent]\n}>()\n\nfunction update(value: number): void {\n emit('update:modelValue', Math.min(props.max, Math.max(props.min, value)))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (props.disabled) return\n const decrement = props.orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp'\n const increment = props.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown'\n if (event.key === decrement) update(props.modelValue - props.step)\n else if (event.key === increment) update(props.modelValue + props.step)\n else if (event.key === 'Home') update(props.min)\n else if (event.key === 'End') update(props.max)\n else return\n event.preventDefault()\n}\n</script>\n\n<template>\n <div\n role=\"separator\"\n :tabindex=\"disabled ? -1 : 0\"\n :class=\"[\n 'mint-layout-resize-handle',\n `mint-layout-resize-handle--${orientation}`,\n edge ? `mint-layout-resize-handle--edge-${edge}` : '',\n ]\"\n :aria-label=\"label\"\n :aria-orientation=\"orientation\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-valuenow=\"modelValue\"\n :aria-disabled=\"disabled || undefined\"\n @pointerdown=\"!disabled && emit('resize-start', $event)\"\n @keydown=\"handleKeydown\"\n >\n <span class=\"mint-layout-resize-handle__bar\" aria-hidden=\"true\" />\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Accessible pointer and keyboard handle for resizable workbench panes. */\ninterface Props {\n modelValue: number\n min: number\n max: number\n label: string\n orientation: 'vertical' | 'horizontal'\n edge?: 'left' | 'right'\n step?: number\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n edge: undefined,\n step: 10,\n disabled: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number]\n 'resize-start': [event: PointerEvent]\n}>()\n\nfunction update(value: number): void {\n emit('update:modelValue', Math.min(props.max, Math.max(props.min, value)))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (props.disabled) return\n const decrement = props.orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp'\n const increment = props.orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown'\n if (event.key === decrement) update(props.modelValue - props.step)\n else if (event.key === increment) update(props.modelValue + props.step)\n else if (event.key === 'Home') update(props.min)\n else if (event.key === 'End') update(props.max)\n else return\n event.preventDefault()\n}\n</script>\n\n<template>\n <div\n role=\"separator\"\n :tabindex=\"disabled ? -1 : 0\"\n :class=\"[\n 'mint-layout-resize-handle',\n `mint-layout-resize-handle--${orientation}`,\n edge ? `mint-layout-resize-handle--edge-${edge}` : '',\n ]\"\n :aria-label=\"label\"\n :aria-orientation=\"orientation\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-valuenow=\"modelValue\"\n :aria-disabled=\"disabled || undefined\"\n @pointerdown=\"!disabled && emit('resize-start', $event)\"\n @keydown=\"handleKeydown\"\n >\n <span class=\"mint-layout-resize-handle__bar\" aria-hidden=\"true\" />\n </div>\n</template>\n","import { computed, onBeforeUnmount, shallowRef, toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nexport interface ResizePanelWidthConstraints {\n minWidth: number\n maxWidth: number\n mainMinWidth?: number\n layoutGap?: number\n}\n\nexport interface ResizePercentConstraints {\n minPercent: number\n maxPercent: number\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n\nfunction availablePanelWidth(\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return Math.min(\n constraints.maxWidth,\n containerWidth - (constraints.mainMinWidth ?? 0) - (constraints.layoutGap ?? 0),\n )\n}\n\nexport function resizedLeadingPanelWidth(\n startWidth: number,\n deltaX: number,\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return Math.round(clamp(\n startWidth + deltaX,\n constraints.minWidth,\n Math.max(constraints.minWidth, availablePanelWidth(containerWidth, constraints)),\n ))\n}\n\nexport function resizedTrailingPanelWidth(\n startWidth: number,\n deltaX: number,\n containerWidth: number,\n constraints: ResizePanelWidthConstraints,\n): number {\n return resizedLeadingPanelWidth(startWidth, -deltaX, containerWidth, constraints)\n}\n\nexport function resizedVerticalSplitPercent(\n startPercent: number,\n deltaY: number,\n containerHeight: number,\n constraints: ResizePercentConstraints,\n): number {\n if (containerHeight <= 0) return startPercent\n return Math.round(clamp(\n startPercent + (deltaY / containerHeight) * 100,\n constraints.minPercent,\n constraints.maxPercent,\n ))\n}\n\nexport interface ManualLayoutResizeContext<TKind extends string> {\n kind: TKind\n startValue: number\n deltaX: number\n deltaY: number\n containerRect: DOMRectReadOnly\n secondaryRect: DOMRectReadOnly | null\n}\n\nexport interface ManualLayoutResizeTarget<TKind extends string> {\n cursor?: string\n getContainerElement: () => HTMLElement | null\n getSecondaryElement?: () => HTMLElement | null\n getStartValue: () => number\n onResize: (context: ManualLayoutResizeContext<TKind>) => void\n}\n\n/** Coordinates pointer-driven resizing for one or more layout splitters. */\nexport function useManualLayoutResize<TKind extends string>(options: {\n enabled: MaybeRefOrGetter<boolean>\n resolveTarget: (kind: TKind) => ManualLayoutResizeTarget<TKind> | null\n}) {\n const activeResize = shallowRef<{\n kind: TKind\n startClientX: number\n startClientY: number\n startValue: number\n containerRect: DOMRectReadOnly\n secondaryRect: DOMRectReadOnly | null\n cursor: string\n } | null>(null)\n const isResizing = computed(() => activeResize.value !== null)\n let previousBodyCursor = ''\n let previousBodyUserSelect = ''\n\n function stopResize(): void {\n if (!activeResize.value) return\n activeResize.value = null\n window.removeEventListener('pointermove', handlePointerMove)\n window.removeEventListener('pointerup', stopResize)\n window.removeEventListener('pointercancel', stopResize)\n if (typeof document !== 'undefined') {\n document.body.style.cursor = previousBodyCursor\n document.body.style.userSelect = previousBodyUserSelect\n }\n }\n\n function handlePointerMove(event: PointerEvent): void {\n const state = activeResize.value\n if (!state) return\n options.resolveTarget(state.kind)?.onResize({\n kind: state.kind,\n startValue: state.startValue,\n deltaX: event.clientX - state.startClientX,\n deltaY: event.clientY - state.startClientY,\n containerRect: state.containerRect,\n secondaryRect: state.secondaryRect,\n })\n }\n\n function startResize(kind: TKind, event: PointerEvent): void {\n if (!toValue(options.enabled) || event.button !== 0) return\n const target = options.resolveTarget(kind)\n const containerRect = target?.getContainerElement()?.getBoundingClientRect()\n if (!target || !containerRect) return\n\n event.preventDefault()\n if (event.currentTarget instanceof HTMLElement) {\n event.currentTarget.setPointerCapture(event.pointerId)\n }\n const secondary = target.getSecondaryElement?.() ?? null\n activeResize.value = {\n kind,\n startClientX: event.clientX,\n startClientY: event.clientY,\n startValue: target.getStartValue(),\n containerRect,\n secondaryRect: secondary?.getBoundingClientRect() ?? null,\n cursor: target.cursor ?? 'col-resize',\n }\n\n if (typeof document !== 'undefined') {\n previousBodyCursor = document.body.style.cursor\n previousBodyUserSelect = document.body.style.userSelect\n document.body.style.cursor = activeResize.value.cursor\n document.body.style.userSelect = 'none'\n }\n window.addEventListener('pointermove', handlePointerMove)\n window.addEventListener('pointerup', stopResize)\n window.addEventListener('pointercancel', stopResize)\n }\n\n function isResizingKind(kind: TKind): boolean {\n return activeResize.value?.kind === kind\n }\n\n watch(() => toValue(options.enabled), enabled => { if (!enabled) stopResize() })\n onBeforeUnmount(stopResize)\n\n return { activeResize, isResizing, isResizingKind, startResize, stopResize }\n}\n","// Application shell components (`@morscherlab/mint-sdk/shell`).\n\n// Layout components\nexport { default as AppTopBar } from './components/AppTopBar.vue'\nexport { default as AppSidebar } from './components/AppSidebar.vue'\nexport { default as AppLayout } from './components/AppLayout.vue'\nexport { default as LayoutResizeHandle } from './components/LayoutResizeHandle.vue'\n\n// Headless interaction composables\nexport {\n useEventListener,\n type EventListenerEnabled,\n type EventFor,\n type EventListenerStop,\n type EventMapFor,\n type EventTargetGetter,\n type EventTargetLike,\n type UseEventListenerObjectOptions,\n type UseEventListenerOptions,\n} from './composables/useEventListener'\nexport {\n useDebouncedWatch,\n type DebouncedWatchCallback,\n type DebouncedWatchCleanup,\n type DebouncedWatchSource,\n type UseDebouncedWatchOptions,\n type UseDebouncedWatchReturn,\n} from './composables/useDebouncedWatch'\nexport {\n useFocusTrap,\n type UseFocusTrapOptions,\n type UseFocusTrapReturn,\n} from './composables/useFocusTrap'\nexport {\n useRovingFocus,\n type UseRovingFocusOptions,\n type UseRovingFocusReturn,\n} from './composables/useRovingFocus'\nexport {\n reorderList,\n useListReorder,\n useReorderAnnouncer,\n REORDER_ANNOUNCER_STYLE,\n type ListReorderMove,\n type UseListReorderOptions,\n type UseListReorderReturn,\n type UseReorderAnnouncerReturn,\n} from './composables/useListReorder'\nexport {\n useMenuKeyboard,\n type UseMenuKeyboardOptions,\n type UseMenuKeyboardReturn,\n} from './composables/useMenuKeyboard'\n\n// Layout, selection, expansion and sort primitives\nexport {\n resizedLeadingPanelWidth,\n resizedTrailingPanelWidth,\n resizedVerticalSplitPercent,\n useManualLayoutResize,\n type ManualLayoutResizeContext,\n type ManualLayoutResizeTarget,\n type ResizePanelWidthConstraints,\n type ResizePercentConstraints,\n} from './composables/useManualLayoutResize'\nexport {\n useSelectionLimit,\n type SelectionLimitSource,\n type UseSelectionLimitOptions,\n type UseSelectionLimitReturn,\n} from './composables/useSelectionLimit'\nexport {\n useListSelection,\n type ListSelectionSource,\n type ListSelectionValue,\n type UseListSelectionOptions,\n type UseListSelectionReturn,\n type WidenListSelectionValue,\n} from './composables/useListSelection'\nexport {\n useExpansionSet,\n type ExpansionSetSource,\n type UseExpansionSetOptions,\n type UseExpansionSetReturn,\n} from './composables/useExpansionSet'\nexport {\n compareSortValues,\n useSortedItems,\n type CompareSortValuesOptions,\n type SortComparator,\n type SortComparatorContext,\n type SortDescriptor,\n type SortedItemsSource,\n type SortOrder,\n type UseSortedItemsOptions,\n type UseSortedItemsReturn,\n} from './composables/useSortedItems'\nexport {\n usePluginWorkspace,\n type PluginWorkspaceSlotsLike,\n type UsePluginWorkspaceOptions,\n type UsePluginWorkspaceReturn,\n} from './composables/usePluginWorkspace'\n"],"mappings":"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"}
package/dist/shell.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { i as useEventListener, r as useFocusTrap } from "./useDropdownState-8yWMu-7_.js";
2
2
  import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-DnK_1Q_S.js";
3
3
  import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-DPynGrCj.js";
4
- import { _ as AppLayout_default, f as AppTopBar_default, t as AppSidebar_default, v as usePluginWorkspace } from "./AppSidebar-DGK5i-hJ.js";
4
+ import { _ as AppLayout_default, f as AppTopBar_default, t as AppSidebar_default, v as usePluginWorkspace } from "./AppSidebar-CIXJBzDv.js";
5
5
  import { t as useDebouncedWatch } from "./useDebouncedWatch-BPwyl6eS.js";
6
6
  import { t as useExpansionSet } from "./useExpansionSet-CvoNMZJi.js";
7
- import { a as useManualLayoutResize, i as resizedVerticalSplitPercent, n as resizedLeadingPanelWidth, o as LayoutResizeHandle_default, r as resizedTrailingPanelWidth } from "./shell-BIH8Rc21.js";
7
+ import { a as useManualLayoutResize, i as resizedVerticalSplitPercent, n as resizedLeadingPanelWidth, o as LayoutResizeHandle_default, r as resizedTrailingPanelWidth } from "./shell-lDf_EY-x.js";
8
8
  export { AppLayout_default as AppLayout, AppSidebar_default as AppSidebar, AppTopBar_default as AppTopBar, LayoutResizeHandle_default as LayoutResizeHandle, REORDER_ANNOUNCER_STYLE, compareSortValues, reorderList, resizedLeadingPanelWidth, resizedTrailingPanelWidth, resizedVerticalSplitPercent, useDebouncedWatch, useEventListener, useExpansionSet, useFocusTrap, useListReorder, useListSelection, useManualLayoutResize, useMenuKeyboard, usePluginWorkspace, useReorderAnnouncer, useRovingFocus, useSelectionLimit, useSortedItems };
package/dist/styles.css CHANGED
@@ -2503,6 +2503,161 @@ button, input, select, textarea {
2503
2503
  white-space: nowrap;
2504
2504
  user-select: none;
2505
2505
  }
2506
+
2507
+ /* ─── Run slot: [ experiment | job ] ───
2508
+ While a job shows, one border wraps the experiment chip and the job
2509
+ segment, as the experiment popover does for Save. The wrapper does not
2510
+ clip: the popover panel and the focus rings reach outside it, so each
2511
+ segment rounds its own outer corners. The idle Jobs button stands apart
2512
+ with its own border. */
2513
+ .mint-topbar__run-slot {
2514
+ display: inline-flex;
2515
+ align-items: center;
2516
+ gap: 0.5rem;
2517
+ min-width: 0;
2518
+ }
2519
+
2520
+ .mint-topbar__run-slot--joined {
2521
+ gap: 0;
2522
+ border: 1px solid var(--border-color);
2523
+ border-radius: var(--radius-md);
2524
+ background: var(--bg-card);
2525
+ }
2526
+
2527
+ .mint-topbar__run-slot--joined .mint-experiment-popover,
2528
+ .mint-topbar__run-slot--joined .mint-experiment-popover__trigger {
2529
+ border: 0;
2530
+ border-radius: calc(var(--radius-md) - 1px) 0 0 calc(var(--radius-md) - 1px);
2531
+ }
2532
+
2533
+ /* The job takes the name's place: the name folds away while the job grows in,
2534
+ and the code badge stays. The name stays in the accessible name. A trigger
2535
+ with no code, the empty placeholder and the error text keep their text. */
2536
+ .mint-topbar__run-slot .mint-experiment-popover__trigger-text {
2537
+ transition:
2538
+ max-width 200ms ease,
2539
+ opacity 150ms ease,
2540
+ margin 200ms ease;
2541
+ }
2542
+
2543
+ .mint-topbar__run-slot--joined
2544
+ .mint-experiment-popover__trigger:has(.mint-exp-code)
2545
+ .mint-experiment-popover__trigger-text {
2546
+ max-width: 0 !important; /* beats the inline maxNameWidth */
2547
+ margin-inline-start: -0.5rem; /* takes back the trigger gap */
2548
+ opacity: 0;
2549
+ }
2550
+
2551
+ .mint-topbar__job {
2552
+ display: inline-flex;
2553
+ max-width: 6rem; /* close to the content (icon + bar, or "Jobs"), so the fold is even */
2554
+ overflow: hidden;
2555
+ align-items: center;
2556
+ gap: 0.375rem;
2557
+ flex-shrink: 0;
2558
+ height: 30px;
2559
+ padding: 0 0.625rem;
2560
+ border: 0;
2561
+ background: transparent;
2562
+ color: var(--text-secondary);
2563
+ font: inherit;
2564
+ font-size: 0.75rem;
2565
+ font-weight: 500;
2566
+ white-space: nowrap;
2567
+ cursor: pointer;
2568
+ transition: background-color var(--mint-transition);
2569
+ }
2570
+
2571
+ .mint-topbar__run-slot--joined .mint-topbar__job {
2572
+ border-radius: calc(var(--radius-md) - 1px);
2573
+ }
2574
+
2575
+ .mint-topbar__run-slot--joined .mint-experiment-popover + .mint-topbar__job {
2576
+ border-left: 1px solid var(--border-color);
2577
+ border-radius: 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0;
2578
+ }
2579
+
2580
+ .mint-topbar__job--idle {
2581
+ height: 32px;
2582
+ border: 1px solid var(--border-color);
2583
+ border-radius: var(--radius-md);
2584
+ background: var(--bg-card);
2585
+ }
2586
+
2587
+ .mint-topbar__job--idle:hover,
2588
+ .mint-topbar__job--neutral:hover {
2589
+ background: var(--bg-hover);
2590
+ }
2591
+
2592
+ .mint-topbar__job:focus-visible {
2593
+ outline: none;
2594
+ box-shadow: inset var(--focus-ring);
2595
+ }
2596
+
2597
+ .mint-topbar__job--primary { background: var(--color-primary-soft); color: var(--_ink-primary); }
2598
+ .mint-topbar__job--warning { background: var(--mint-warning-bg); color: var(--mint-warning-text); }
2599
+ .mint-topbar__job--success { background: var(--mint-success-bg); color: color-mix(in srgb, var(--mint-success) 50%, var(--text-primary)); }
2600
+ .mint-topbar__job--error { background: var(--mint-error-bg); color: var(--_ink-error); }
2601
+
2602
+ .mint-topbar__job--primary:hover,
2603
+ .mint-topbar__job--warning:hover,
2604
+ .mint-topbar__job--success:hover,
2605
+ .mint-topbar__job--error:hover {
2606
+ filter: brightness(0.97);
2607
+ }
2608
+
2609
+ .mint-topbar__job-icon {
2610
+ flex-shrink: 0;
2611
+ }
2612
+
2613
+ .mint-topbar__job-icon--spin {
2614
+ animation: mint-topbar-job-spin 1s linear infinite;
2615
+ }
2616
+
2617
+ @keyframes mint-topbar-job-spin {
2618
+ to { transform: rotate(360deg); }
2619
+ }
2620
+
2621
+ .mint-topbar__job-bar {
2622
+ width: 2rem;
2623
+ height: 4px;
2624
+ border-radius: 2px;
2625
+ background: var(--border-color);
2626
+ overflow: hidden;
2627
+ }
2628
+
2629
+ .mint-topbar__job-bar > span {
2630
+ display: block;
2631
+ height: 100%;
2632
+ background: var(--color-primary);
2633
+ transition: width var(--mint-transition);
2634
+ }
2635
+
2636
+ /* Enter and leave: the job grows in from zero width and folds back out. */
2637
+ .mint-topbar-job-enter-active,
2638
+ .mint-topbar-job-leave-active {
2639
+ transition:
2640
+ max-width 200ms ease,
2641
+ padding 200ms ease,
2642
+ opacity 150ms ease;
2643
+ }
2644
+
2645
+ .mint-topbar-job-enter-from,
2646
+ .mint-topbar-job-leave-to {
2647
+ max-width: 0;
2648
+ padding-inline: 0;
2649
+ opacity: 0;
2650
+ }
2651
+
2652
+ /* Screen-reader only: announces status changes of the shown job. */
2653
+ .mint-topbar__job-status {
2654
+ position: absolute;
2655
+ width: 1px;
2656
+ height: 1px;
2657
+ overflow: hidden;
2658
+ clip-path: inset(50%);
2659
+ white-space: nowrap;
2660
+ }
2506
2661
  /* BaseButton Component Styles */
2507
2662
 
2508
2663
  .mint-button {
@@ -16785,13 +16940,26 @@ button.mint-unit-input__unit:focus-visible {
16785
16940
  }
16786
16941
 
16787
16942
  /* Footer with clear selection */
16943
+ .mint-experiment-selector__description {
16944
+ padding: 0 1.25rem 0.75rem;
16945
+ font-size: 0.8125rem;
16946
+ color: var(--text-secondary);
16947
+ }
16948
+
16788
16949
  .mint-experiment-selector__footer {
16789
16950
  display: flex;
16951
+ align-items: center;
16952
+ gap: 0.75rem;
16790
16953
  justify-content: flex-start;
16791
16954
  padding: 0.5rem 1.25rem 0.75rem;
16792
16955
  border-top: 1px solid var(--border-light);
16793
16956
  }
16794
16957
 
16958
+ .mint-experiment-selector__footer-slot {
16959
+ flex: 1;
16960
+ min-width: 0;
16961
+ }
16962
+
16795
16963
  .mint-experiment-selector__clear-btn {
16796
16964
  padding: 0.25rem 0;
16797
16965
  border: none;
@@ -17332,54 +17500,79 @@ button.mint-unit-input__unit:focus-visible {
17332
17500
  animation: none;
17333
17501
  }
17334
17502
  }
17335
- /* AppTopBar page selector — left-side route/page dropdown.
17336
- Trigger speaks the field language (5a): 36px (the identity tile height), hover changes the background
17337
- only, open = field focus, inline 12px chevron. The menu keeps the 1.2 panel
17338
- (own card, tinted active row) rather than .mint-popover + .mint-menu-item. */
17503
+ /* AppTopBar page selector — design v2 option C: "<plugin> / <page>" as one switcher.
17504
+ The crumb holds the plugin name, a slash and the tinted 32px trigger. The menu keeps its own
17505
+ card (not .mint-popover): a "<plugin> pages" title, then one row per page with its hint and number key. */
17506
+
17507
+ /* Shrinks with the bar: the plugin name and the page label truncate instead of overlapping the nav. */
17508
+ .mint-page-selector__crumb {
17509
+ display: inline-flex;
17510
+ align-items: center;
17511
+ gap: 0.375rem;
17512
+ min-width: 0;
17513
+ flex-shrink: 1;
17514
+ }
17515
+
17516
+ .mint-page-selector__plugin {
17517
+ min-width: 0;
17518
+ font-size: 0.875rem;
17519
+ font-weight: 600;
17520
+ color: var(--text-primary);
17521
+ white-space: nowrap;
17522
+ overflow: hidden;
17523
+ text-overflow: ellipsis;
17524
+ }
17339
17525
 
17340
- /* Shrinks down to its inline min-width (11.25rem) so a crowded bar truncates the label instead of overlapping the nav. */
17526
+ .mint-page-selector__slash {
17527
+ flex-shrink: 0;
17528
+ font-size: 1.125rem;
17529
+ font-weight: 300;
17530
+ line-height: 1;
17531
+ color: var(--text-muted);
17532
+ }
17533
+
17534
+ /* Anchors the menu under the trigger, not under the plugin name. */
17341
17535
  .mint-page-selector {
17342
17536
  position: relative;
17343
- flex-shrink: 1;
17537
+ display: flex;
17538
+ min-width: 0;
17344
17539
  }
17345
17540
 
17346
17541
  .mint-page-selector__trigger {
17347
17542
  display: inline-flex;
17348
17543
  align-items: center;
17349
- gap: 0.5rem;
17350
- width: 100%;
17351
- height: 2.25rem;
17352
- padding: 0 0.5rem 0 0.4375rem;
17353
- border: 1px solid var(--border-color);
17354
- background: var(--bg-card);
17544
+ gap: 0.375rem;
17545
+ min-width: 0;
17546
+ max-width: 100%;
17547
+ height: 2rem;
17548
+ padding: 0 0.5rem 0 0.375rem;
17549
+ border: 0;
17550
+ background: var(--color-primary-soft);
17355
17551
  color: var(--text-primary);
17356
17552
  border-radius: var(--radius-md);
17357
17553
  font-size: 0.8125rem;
17358
- font-weight: 500;
17554
+ font-weight: 600;
17359
17555
  font-family: inherit;
17360
17556
  cursor: pointer;
17361
17557
  transition:
17362
17558
  background-color var(--mint-transition),
17363
- border-color var(--mint-transition),
17364
17559
  box-shadow var(--mint-transition);
17365
17560
  }
17366
17561
 
17367
- .mint-page-selector__trigger:hover:not(.mint-page-selector__trigger--open) {
17368
- background: var(--bg-hover);
17562
+ .mint-page-selector__trigger:hover {
17563
+ background: color-mix(in srgb, var(--color-primary) 16%, transparent);
17369
17564
  }
17370
17565
 
17371
- .mint-page-selector__trigger:focus-visible,
17372
- .mint-page-selector__trigger--open {
17566
+ .mint-page-selector__trigger:focus-visible {
17373
17567
  outline: none;
17374
- border-color: var(--color-primary);
17375
- box-shadow: var(--focus-ring-soft);
17568
+ box-shadow: var(--focus-ring-offset);
17376
17569
  }
17377
17570
 
17378
17571
  /* Page icon tile is neutral; the plugin carries the color. */
17379
17572
  .mint-page-selector__icon {
17380
17573
  width: 1.25rem;
17381
17574
  height: 1.25rem;
17382
- border-radius: var(--radius-sm);
17575
+ border-radius: var(--radius);
17383
17576
  background: var(--bg-tertiary);
17384
17577
  color: var(--text-secondary-strong);
17385
17578
  display: grid;
@@ -17400,7 +17593,7 @@ button.mint-unit-input__unit:focus-visible {
17400
17593
  .mint-page-selector__trigger-metadata-icon.mint-plugin-icon--sm {
17401
17594
  width: 1.25rem;
17402
17595
  height: 1.25rem;
17403
- border-radius: var(--radius-sm);
17596
+ border-radius: var(--radius);
17404
17597
  }
17405
17598
 
17406
17599
  .mint-page-selector__icon-fallback {
@@ -17410,7 +17603,6 @@ button.mint-unit-input__unit:focus-visible {
17410
17603
  }
17411
17604
 
17412
17605
  .mint-page-selector__label {
17413
- flex: 1;
17414
17606
  min-width: 0;
17415
17607
  text-align: left;
17416
17608
  white-space: nowrap;
@@ -17418,7 +17610,6 @@ button.mint-unit-input__unit:focus-visible {
17418
17610
  text-overflow: ellipsis;
17419
17611
  }
17420
17612
 
17421
- /* The chevron sits inline; the wrap no longer draws a tile. */
17422
17613
  .mint-page-selector__chevron-wrap {
17423
17614
  display: inline-flex;
17424
17615
  color: var(--text-secondary);
@@ -17435,38 +17626,46 @@ button.mint-unit-input__unit:focus-visible {
17435
17626
  transform: rotate(180deg);
17436
17627
  }
17437
17628
 
17629
+ /* max-height: 8 two-line hint rows (8 x 68px) + title (~25px) + padding (8px) = ~577px; a 9th row scrolls. A short window caps it. */
17438
17630
  .mint-page-selector__menu {
17439
17631
  position: absolute;
17632
+ box-sizing: border-box;
17440
17633
  top: calc(100% + 0.375rem);
17441
17634
  left: 0;
17442
- width: 16.25rem;
17635
+ width: 18.75rem;
17636
+ max-height: min(36.25rem, calc(100vh - 6rem));
17637
+ overflow-y: auto;
17443
17638
  background: var(--bg-card);
17444
17639
  border: 1px solid var(--border-color);
17445
17640
  border-radius: var(--radius-lg);
17446
17641
  box-shadow: var(--shadow-md);
17447
- padding: 0.375rem;
17642
+ padding: 0.25rem;
17448
17643
  z-index: 50;
17449
17644
  }
17450
17645
 
17646
+ /* The mockup's 10px uppercase eyebrow breaks rules 2a (no uppercase) and 8d (UI text >= 11px): 11px, sentence case. */
17451
17647
  .mint-page-selector__menu-title {
17452
- padding: 0.375rem 0.625rem 0.5rem;
17453
- font-size: 0.75rem;
17648
+ padding: 0.375rem 0.5rem 0.25rem;
17649
+ font-family: var(--font-mono);
17650
+ font-size: 0.6875rem;
17454
17651
  font-weight: 500;
17455
- color: var(--text-secondary);
17652
+ letter-spacing: 0.06em;
17653
+ color: var(--text-muted);
17456
17654
  }
17457
17655
 
17458
17656
  .mint-page-selector__item {
17459
17657
  display: flex;
17460
- align-items: center;
17658
+ box-sizing: border-box;
17659
+ align-items: flex-start;
17461
17660
  gap: 0.625rem;
17462
17661
  width: 100%;
17463
- padding: 0.5rem 0.625rem;
17662
+ padding: 0.5rem;
17464
17663
  border: 0;
17465
17664
  background: transparent;
17466
- border-radius: 0.4375rem;
17665
+ border-radius: var(--radius);
17467
17666
  color: var(--text-primary);
17468
17667
  font-size: 0.8125rem;
17469
- font-weight: 500;
17668
+ line-height: 1.4;
17470
17669
  font-family: inherit;
17471
17670
  text-align: left;
17472
17671
  text-decoration: none;
@@ -17474,13 +17673,22 @@ button.mint-unit-input__unit:focus-visible {
17474
17673
  transition: background-color var(--mint-transition);
17475
17674
  }
17476
17675
 
17477
- .mint-page-selector__item:hover:not(.mint-page-selector__item--disabled) {
17676
+ /* A row without a hint has one line: centre it on the icon tile. */
17677
+ .mint-page-selector__item:not(:has(.mint-page-selector__item-hint)) {
17678
+ align-items: center;
17679
+ }
17680
+
17681
+ .mint-page-selector__item:hover:not(.mint-page-selector__item--disabled):not(.mint-page-selector__item--active) {
17478
17682
  background: var(--bg-hover);
17479
17683
  }
17480
17684
 
17685
+ .mint-page-selector__item:focus-visible {
17686
+ outline: 2px solid var(--color-primary);
17687
+ outline-offset: -2px;
17688
+ }
17689
+
17481
17690
  .mint-page-selector__item--active {
17482
- background: var(--bg-tertiary);
17483
- font-weight: 600;
17691
+ background: var(--color-primary-soft);
17484
17692
  }
17485
17693
 
17486
17694
  .mint-page-selector__item--disabled {
@@ -17489,9 +17697,9 @@ button.mint-unit-input__unit:focus-visible {
17489
17697
  }
17490
17698
 
17491
17699
  .mint-page-selector__item-icon {
17492
- width: 1.375rem;
17493
- height: 1.375rem;
17494
- border-radius: 0.3125rem;
17700
+ width: 1.75rem;
17701
+ height: 1.75rem;
17702
+ border-radius: var(--radius-md);
17495
17703
  background: var(--bg-tertiary);
17496
17704
  color: var(--text-secondary);
17497
17705
  display: grid;
@@ -17499,6 +17707,10 @@ button.mint-unit-input__unit:focus-visible {
17499
17707
  flex-shrink: 0;
17500
17708
  }
17501
17709
 
17710
+ .mint-page-selector__item-icon .mint-page-selector__icon-fallback {
17711
+ font-size: 0.8125rem;
17712
+ }
17713
+
17502
17714
  .mint-page-selector__item--active .mint-page-selector__item-icon {
17503
17715
  background: var(--color-primary-soft);
17504
17716
  color: var(--color-primary);
@@ -17511,24 +17723,55 @@ button.mint-unit-input__unit:focus-visible {
17511
17723
  }
17512
17724
 
17513
17725
  .mint-page-selector__item-icon svg {
17514
- width: 0.8125rem;
17515
- height: 0.8125rem;
17726
+ width: 0.9375rem;
17727
+ height: 0.9375rem;
17516
17728
  }
17517
17729
 
17518
17730
  .mint-page-selector__metadata-icon.mint-plugin-icon--sm {
17519
- width: 1.375rem;
17520
- height: 1.375rem;
17521
- border-radius: 0.3125rem;
17731
+ width: 1.75rem;
17732
+ height: 1.75rem;
17733
+ border-radius: var(--radius-md);
17522
17734
  }
17523
17735
 
17524
- .mint-page-selector__item-label {
17736
+ .mint-page-selector__item-text {
17525
17737
  flex: 1;
17526
17738
  min-width: 0;
17739
+ display: grid;
17740
+ gap: 1px;
17741
+ }
17742
+
17743
+ .mint-page-selector__item-label {
17744
+ font-weight: 600;
17527
17745
  overflow: hidden;
17528
17746
  text-overflow: ellipsis;
17529
17747
  white-space: nowrap;
17530
17748
  }
17531
17749
 
17750
+ /* --_ink-primary is --color-primary-hover in light mode and stays legible in dark mode. */
17751
+ .mint-page-selector__item--active .mint-page-selector__item-label {
17752
+ color: var(--_ink-primary);
17753
+ }
17754
+
17755
+ .mint-page-selector__item-hint {
17756
+ font-size: 0.75rem;
17757
+ line-height: 1.35;
17758
+ color: var(--text-secondary);
17759
+ }
17760
+
17761
+ /* 11px, the rule 8d floor (the mockup has 10.5px). */
17762
+ .mint-page-selector__item-key {
17763
+ flex-shrink: 0;
17764
+ margin-top: 0.125rem;
17765
+ padding: 0 0.25rem;
17766
+ border: 1px solid var(--border-color);
17767
+ border-radius: var(--radius);
17768
+ font-family: var(--font-mono);
17769
+ font-size: 0.6875rem;
17770
+ font-weight: 500;
17771
+ line-height: 1rem;
17772
+ color: var(--text-muted);
17773
+ }
17774
+
17532
17775
  @media (prefers-reduced-motion: reduce) {
17533
17776
  .mint-page-selector__trigger,
17534
17777
  .mint-page-selector__chevron {
@@ -3,7 +3,7 @@ export type * from './generated-ui';
3
3
  export type { AnalysisArtifactStatus, AnalysisArtifactStatusFilter, AnalysisArtifactSummary, AnalysisArtifactDetail, AnalysisArtifactListResponse, AnalysisArtifactTarget, AnalysisArtifactMetadataUpdate, ArtifactSaveMode, ArtifactFileSource, JsonArtifactSavePayload, FileArtifactCreatePayload, FileArtifactUpdatePayload, HandlerFileArtifactCreatePayload, HandlerFileArtifactUpdatePayload, ArtifactSavePayload, HandlerArtifactSavePayload, ArtifactSaveDialogPayload, ArtifactSaveResult, ArtifactSaveHandler, HandlerArtifactSaveHandler, ArtifactSaveDialogHandler, } from './analysisArtifactTypes';
4
4
  export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from './analysisArtifactTypes';
5
5
  export type { FileBrowserLocation, FileBrowserSortKey, FileDirectoryListing, FileDirectoryTree, FileEntry, FileEntryKind, FilePathCrumb, FileSearchResult, FileSelection, ServerMount, } from './fileBrowserTypes';
6
- export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, } from './jobs';
6
+ export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, TopBarJob, } from './jobs';
7
7
  export type { InjectionMetricSeries, InstrumentAlert, InstrumentAlertLevel, InstrumentAlertList, InstrumentBadgeState, InstrumentLiveProgress, InstrumentLiveStatus, InstrumentState, InstrumentStatus, InstrumentStatusReporter, SampleInfo, SampleInfo as InstrumentSampleInfo, SequenceProgress, StatusPanel, } from './instrument';
8
8
  export type { AccessAudience, AccessAudienceInput, AccessPolicy, AccessControlled, PermissionUser, RoleInfo, } from '../permissions';
9
9
  export type { FormFieldType, FieldCondition, FieldValidation, FormFieldSchema, FormOptionInput, FormSectionSchema, FormStepSchema, FormSchema, FieldEnhancement, FormEnhancements, UseFormBuilderReturn, } from './form-builder';
@@ -53,3 +53,12 @@ export interface JobSnapshotPayload {
53
53
  jobs: JobStateInput[];
54
54
  }
55
55
  export type JobStreamData = JobStateInput | JobSnapshotPayload;
56
+ /** What the top-bar run slot shows for the viewer's own job. The plugin picks the job. */
57
+ export interface TopBarJob {
58
+ /** Lifecycle of the shown job; sets the icon and the tone. */
59
+ status: JobStatus;
60
+ /** Tooltip and accessible name, e.g. "Extracting", "Saved to EXP-0142". Not shown as text. */
61
+ label: string;
62
+ /** 0-100; drawn as a small bar after the icon. */
63
+ percent?: number | null;
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morscherlab/mint-sdk",
3
- "version": "1.4.0-beta.12",
3
+ "version": "1.4.0-beta.13",
4
4
  "description": "MINT Platform SDK — Vue 3 components, composables, and types for plugin development. MINT = Mass-spec INtegrated Toolkit.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -65,19 +65,19 @@ export function installMockInterceptor() {
65
65
  * Props:
66
66
  * preselect (boolean, default true) - pre-select the first mock experiment
67
67
  * plugin (PluginInfo, optional) - the integrated plugin, shown as AppTopBar's static identity
68
+ * save (boolean, default true) - show the Save half of the experiment chip
68
69
  */
69
70
  export const ExperimentProvider = defineComponent({
70
71
  props: {
71
72
  preselect: { type: Boolean, default: true },
72
73
  plugin: { type: Object as PropType<PluginInfo>, default: undefined },
74
+ save: { type: Boolean, default: true },
73
75
  },
74
76
  setup(props, { slots }) {
75
77
  ;(window as any).__MINT_PLATFORM__ = { isIntegrated: true, theme: 'system', plugin: props.plugin }
76
78
  installMockInterceptor()
77
79
  const experimentStore = useExperimentStore()
78
- useAppExperiment({
79
- onSave: async () => 'Saved!',
80
- })
80
+ useAppExperiment(props.save ? { onSave: async () => 'Saved!' } : {})
81
81
  if (props.preselect && mockExperiments[0]) {
82
82
  experimentStore.select(mockExperiments[0])
83
83
  }