@morscherlab/mint-sdk 1.5.0-beta.6 → 1.5.0-beta.8

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 (106) hide show
  1. package/dist/{AlertBox-CexONPhA.js → AlertBox-Cai0w7gF.js} +3 -3
  2. package/dist/{AlertBox-CexONPhA.js.map → AlertBox-Cai0w7gF.js.map} +1 -1
  3. package/dist/{AppSidebar-FxlF5_dI.js → AppSidebar-C1DT4nsZ.js} +351 -90
  4. package/dist/AppSidebar-C1DT4nsZ.js.map +1 -0
  5. package/dist/{ConfirmDialog-D9QXFpsy.js → ConfirmDialog-BjFsOpBe.js} +2 -2
  6. package/dist/{ConfirmDialog-D9QXFpsy.js.map → ConfirmDialog-BjFsOpBe.js.map} +1 -1
  7. package/dist/{ExperimentPopover-Bbd6RaoH.js → ExperimentPopover-DYy_s0kI.js} +25 -37
  8. package/dist/ExperimentPopover-DYy_s0kI.js.map +1 -0
  9. package/dist/{ExperimentSelectorModal-CUkKmgfr.js → ExperimentSelectorModal-Bfh5bdkv.js} +5 -5
  10. package/dist/{ExperimentSelectorModal-CUkKmgfr.js.map → ExperimentSelectorModal-Bfh5bdkv.js.map} +1 -1
  11. package/dist/{SegmentedControl-C-sckoJZ.js → SegmentedControl-B8KgyOjd.js} +2 -2
  12. package/dist/{SegmentedControl-C-sckoJZ.js.map → SegmentedControl-B8KgyOjd.js.map} +1 -1
  13. package/dist/{SettingsModal-BIC0dAYc.js → SettingsModal-DPNblTe9.js} +7 -7
  14. package/dist/{SettingsModal-BIC0dAYc.js.map → SettingsModal-DPNblTe9.js.map} +1 -1
  15. package/dist/__tests__/components/AppTopBarCompact.test.d.ts +1 -0
  16. package/dist/__tests__/components/AppTopBarCompactReset.test.d.ts +1 -0
  17. package/dist/__tests__/components/AutoGroupModal.experimentLoad.test.d.ts +1 -0
  18. package/dist/components/AppTopBar.compact.d.ts +5 -0
  19. package/dist/components/AppTopBar.vue.d.ts +17 -17
  20. package/dist/components/PluginWorkspaceView.vue.d.ts +4 -0
  21. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -2
  22. package/dist/components/internal/LucideIconInternal.vue.d.ts +17 -0
  23. package/dist/composables/appLayoutSidebar.d.ts +9 -0
  24. package/dist/composables/useVersionedSave.d.ts +5 -2
  25. package/dist/{controlSchemaModel-C_XqpkgE.js → controlSchemaModel-BtFNZj8t.js} +2 -2
  26. package/dist/{controlSchemaModel-C_XqpkgE.js.map → controlSchemaModel-BtFNZj8t.js.map} +1 -1
  27. package/dist/{data-CfY7o8QC.js → data-CJztFns8.js} +31 -15
  28. package/dist/{data-CfY7o8QC.js.map → data-CJztFns8.js.map} +1 -1
  29. package/dist/data.js +8 -8
  30. package/dist/{experimentStatus-DCn2QKG7.js → experimentStatus-Deokk7Br.js} +2 -2
  31. package/dist/{experimentStatus-DCn2QKG7.js.map → experimentStatus-Deokk7Br.js.map} +1 -1
  32. package/dist/index.js +14 -14
  33. package/dist/{install-QF3Sh82O.js → install-9FkKs0iW.js} +14 -15
  34. package/dist/{install-QF3Sh82O.js.map → install-9FkKs0iW.js.map} +1 -1
  35. package/dist/install.js +1 -1
  36. package/dist/{lab-BcX5JBSY.js → lab-BYhb_cJI.js} +22 -14
  37. package/dist/lab-BYhb_cJI.js.map +1 -0
  38. package/dist/lab.js +4 -4
  39. package/dist/{records-BAymyHAn.js → records-GtiVMlTQ.js} +198 -62
  40. package/dist/records-GtiVMlTQ.js.map +1 -0
  41. package/dist/{runtime-DngeJtdq.js → runtime-DcMsvlaS.js} +29 -12
  42. package/dist/runtime-DcMsvlaS.js.map +1 -0
  43. package/dist/runtime.js +6 -6
  44. package/dist/{shell-CWZi97nW.js → shell-XZYkAZS_.js} +5 -5
  45. package/dist/{shell-CWZi97nW.js.map → shell-XZYkAZS_.js.map} +1 -1
  46. package/dist/shell.js +5 -5
  47. package/dist/styles.css +136 -12
  48. package/dist/types/components.d.ts +22 -2
  49. package/dist/types/index.d.ts +1 -1
  50. package/dist/{useDropdownState-uFIz6Yv8.js → useDropdownState-CcBzUYZ6.js} +14 -5
  51. package/dist/useDropdownState-CcBzUYZ6.js.map +1 -0
  52. package/dist/{useExperimentSamples-DEDAKa2E.js → useExperimentSamples-CpNXvpUn.js} +3 -3
  53. package/dist/{useExperimentSamples-DEDAKa2E.js.map → useExperimentSamples-CpNXvpUn.js.map} +1 -1
  54. package/dist/{useListReorder-W1bzK_bo.js → useListReorder-Bp4EAI2w.js} +3 -3
  55. package/dist/{useListReorder-W1bzK_bo.js.map → useListReorder-Bp4EAI2w.js.map} +1 -1
  56. package/dist/{useRackEditor-Bmtuo0aj.js → useRackEditor-i2bdPUFf.js} +8 -8
  57. package/dist/{useRackEditor-Bmtuo0aj.js.map → useRackEditor-i2bdPUFf.js.map} +1 -1
  58. package/dist/{useRealtime-jOetF2mM.js → useRealtime-BLQEjbuq.js} +3 -3
  59. package/dist/{useRealtime-jOetF2mM.js.map → useRealtime-BLQEjbuq.js.map} +1 -1
  60. package/dist/useRequest-CXyPw3eh.js +76 -0
  61. package/dist/useRequest-CXyPw3eh.js.map +1 -0
  62. package/dist/utils/deprecation.d.ts +2 -0
  63. package/dist/utils/lucideIcon.d.ts +4 -0
  64. package/package.json +1 -1
  65. package/src/__tests__/components/AppTopBar.test.ts +102 -20
  66. package/src/__tests__/components/AppTopBarCompact.test.ts +65 -0
  67. package/src/__tests__/components/AppTopBarCompactReset.test.ts +24 -0
  68. package/src/__tests__/components/AutoGroupModal.experimentLoad.test.ts +58 -0
  69. package/src/__tests__/components/BaseModal.test.ts +33 -2
  70. package/src/__tests__/components/ExperimentPopover.test.ts +32 -0
  71. package/src/__tests__/components/PluginWorkspaceView.test.ts +1 -1
  72. package/src/__tests__/composables/useJobCenter.test.ts +35 -0
  73. package/src/__tests__/composables/useVersionedSave.test.ts +71 -6
  74. package/src/__tests__/styles/menusShellRefresh.test.ts +5 -0
  75. package/src/components/AppLayout.story.vue +5 -5
  76. package/src/components/AppLayout.vue +13 -1
  77. package/src/components/AppTopBar.compact.ts +60 -0
  78. package/src/components/AppTopBar.story.vue +39 -14
  79. package/src/components/AppTopBar.vue +222 -89
  80. package/src/components/BaseModal.vue +16 -5
  81. package/src/components/ExperimentPopover.story.vue +2 -2
  82. package/src/components/ExperimentPopover.vue +6 -22
  83. package/src/components/GeneratedPluginView.vue +0 -1
  84. package/src/components/PluginWorkspaceView.vue +8 -0
  85. package/src/components/internal/AppTopBarPageSelectorInternal.vue +12 -0
  86. package/src/components/internal/AutoGroupModalInternal.vue +14 -3
  87. package/src/components/internal/LucideIconInternal.vue +23 -0
  88. package/src/composables/appLayoutSidebar.ts +11 -0
  89. package/src/composables/useJobCenter.ts +21 -1
  90. package/src/composables/usePluginWorkspace.ts +1 -1
  91. package/src/composables/useVersionedSave.ts +32 -7
  92. package/src/styles/components/app-layout.css +5 -0
  93. package/src/styles/components/app-top-bar.css +128 -8
  94. package/src/types/components.ts +23 -2
  95. package/src/types/index.ts +1 -0
  96. package/src/utils/deprecation.ts +8 -0
  97. package/src/utils/lucideIcon.ts +25 -0
  98. package/src/utils/lucideIconIndex.d.ts +2 -0
  99. package/dist/AppSidebar-FxlF5_dI.js.map +0 -1
  100. package/dist/ExperimentPopover-Bbd6RaoH.js.map +0 -1
  101. package/dist/lab-BcX5JBSY.js.map +0 -1
  102. package/dist/records-BAymyHAn.js.map +0 -1
  103. package/dist/runtime-DngeJtdq.js.map +0 -1
  104. package/dist/useDropdownState-uFIz6Yv8.js.map +0 -1
  105. package/dist/useRequest-D9-3BS-3.js +0 -215
  106. package/dist/useRequest-D9-3BS-3.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { i as useEventListener, o as __exportAll, r as useFocusTrap } from "./useDropdownState-uFIz6Yv8.js";
2
- import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-BAymyHAn.js";
3
- import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-W1bzK_bo.js";
4
- import { C as usePluginWorkspace, S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding } from "./AppSidebar-FxlF5_dI.js";
1
+ import { i as useEventListener, o as __exportAll, r as useFocusTrap } from "./useDropdownState-CcBzUYZ6.js";
2
+ import { D as useMenuKeyboard, U as useListSelection, W as useSelectionLimit, z as useRovingFocus } from "./records-GtiVMlTQ.js";
3
+ import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-Bp4EAI2w.js";
4
+ import { S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding, w as usePluginWorkspace } from "./AppSidebar-C1DT4nsZ.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";
@@ -199,4 +199,4 @@ var shell_exports = /* @__PURE__ */ __exportAll({
199
199
  //#endregion
200
200
  export { useManualLayoutResize as a, resizedVerticalSplitPercent as i, resizedLeadingPanelWidth as n, LayoutResizeHandle_default as o, resizedTrailingPanelWidth as r, shell_exports as t };
201
201
 
202
- //# sourceMappingURL=shell-CWZi97nW.js.map
202
+ //# sourceMappingURL=shell-XZYkAZS_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-CWZi97nW.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\n// Onboarding: tours, the Getting started checklist and what's-new hints\nexport {\n ANCHOR_WAIT_MS,\n defineOnboarding,\n provideOnboarding,\n useOnboarding,\n ONBOARDING_KEY,\n type OnboardingActiveStep,\n type OnboardingDefinition,\n type OnboardingNews,\n type OnboardingState,\n type OnboardingStep,\n type OnboardingTask,\n type OnboardingTour,\n type ProvideOnboardingOptions,\n} from './composables/useOnboarding'\n"],"mappings":"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"}
1
+ {"version":3,"file":"shell-XZYkAZS_.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\n// Onboarding: tours, the Getting started checklist and what's-new hints\nexport {\n ANCHOR_WAIT_MS,\n defineOnboarding,\n provideOnboarding,\n useOnboarding,\n ONBOARDING_KEY,\n type OnboardingActiveStep,\n type OnboardingDefinition,\n type OnboardingNews,\n type OnboardingState,\n type OnboardingStep,\n type OnboardingTask,\n type OnboardingTour,\n type ProvideOnboardingOptions,\n} from './composables/useOnboarding'\n"],"mappings":"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"}
package/dist/shell.js CHANGED
@@ -1,8 +1,8 @@
1
- import { i as useEventListener, r as useFocusTrap } from "./useDropdownState-uFIz6Yv8.js";
2
- import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-BAymyHAn.js";
3
- import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-W1bzK_bo.js";
4
- import { C as usePluginWorkspace, S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding } from "./AppSidebar-FxlF5_dI.js";
1
+ import { i as useEventListener, r as useFocusTrap } from "./useDropdownState-CcBzUYZ6.js";
2
+ import { D as useMenuKeyboard, U as useListSelection, W as useSelectionLimit, z as useRovingFocus } from "./records-GtiVMlTQ.js";
3
+ import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-Bp4EAI2w.js";
4
+ import { S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding, w as usePluginWorkspace } from "./AppSidebar-C1DT4nsZ.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-CWZi97nW.js";
7
+ import { a as useManualLayoutResize, i as resizedVerticalSplitPercent, n as resizedLeadingPanelWidth, o as LayoutResizeHandle_default, r as resizedTrailingPanelWidth } from "./shell-XZYkAZS_.js";
8
8
  export { ANCHOR_WAIT_MS, AppLayout_default as AppLayout, AppSidebar_default as AppSidebar, AppTopBar_default as AppTopBar, LayoutResizeHandle_default as LayoutResizeHandle, ONBOARDING_KEY, REORDER_ANNOUNCER_STYLE, compareSortValues, defineOnboarding, provideOnboarding, reorderList, resizedLeadingPanelWidth, resizedTrailingPanelWidth, resizedVerticalSplitPercent, useDebouncedWatch, useEventListener, useExpansionSet, useFocusTrap, useListReorder, useListSelection, useManualLayoutResize, useMenuKeyboard, useOnboarding, usePluginWorkspace, useReorderAnnouncer, useRovingFocus, useSelectionLimit, useSortedItems };
package/dist/styles.css CHANGED
@@ -122,12 +122,12 @@
122
122
  overflow-wrap: anywhere;
123
123
  }
124
124
 
125
- .mint-generated-workspace[data-v-90271c34] {
125
+ .mint-generated-workspace[data-v-7ba9e342] {
126
126
  min-width: 0;
127
127
  min-height: 0;
128
128
  overflow-y: auto;
129
129
  }
130
- .mint-generated-workspace__loading[data-v-90271c34] {
130
+ .mint-generated-workspace__loading[data-v-7ba9e342] {
131
131
  display: flex;
132
132
  flex: 1;
133
133
  align-items: center;
@@ -135,12 +135,12 @@
135
135
  gap: 0.75rem;
136
136
  color: var(--text-secondary);
137
137
  }
138
- .mint-generated-workspace__resources[data-v-90271c34] {
138
+ .mint-generated-workspace__resources[data-v-7ba9e342] {
139
139
  color: var(--text-muted);
140
140
  font-family: var(--font-mono);
141
141
  font-size: 0.75rem;
142
142
  }
143
- .mint-generated-workspace__description[data-v-90271c34] {
143
+ .mint-generated-workspace__description[data-v-7ba9e342] {
144
144
  margin: 0 0 var(--mint-gutter);
145
145
  color: var(--text-secondary);
146
146
  }
@@ -1707,6 +1707,10 @@ button, input, select, textarea {
1707
1707
  }
1708
1708
  }
1709
1709
 
1710
+ /* An AppTopBar in the layout renders the drawer button itself. */
1711
+ .mint-layout--responsive-sidebar:has(.mint-topbar__sidebar-toggle) .mint-layout__sidebar-toggle {
1712
+ display: none;
1713
+ }
1710
1714
  /* AppSidebar Component Styles */
1711
1715
 
1712
1716
  .mint-sidebar {
@@ -2266,6 +2270,8 @@ button, input, select, textarea {
2266
2270
  padding: 0.75rem 1rem;
2267
2271
  background-color: var(--bg-secondary);
2268
2272
  box-sizing: border-box;
2273
+ /* The two-row layout follows the bar's own width, not the window's. */
2274
+ container: mint-topbar / inline-size;
2269
2275
  }
2270
2276
 
2271
2277
  /* Main container layout — equal side columns keep the centre nav on the bar
@@ -2326,11 +2332,62 @@ button, input, select, textarea {
2326
2332
  grid-column: 3;
2327
2333
  display: flex;
2328
2334
  align-items: center;
2329
- gap: 0.125rem;
2335
+ gap: 0.375rem;
2330
2336
  min-width: 0;
2331
2337
  justify-content: flex-end;
2332
2338
  }
2333
2339
 
2340
+ /* Context group (standalone badge, run slot, onboarding, plugin buttons), then
2341
+ the fixed tail: theme, settings and the host's account controls, always last. */
2342
+ .mint-topbar__context,
2343
+ .mint-topbar__tail {
2344
+ display: flex;
2345
+ align-items: center;
2346
+ gap: 0.125rem;
2347
+ min-width: 0;
2348
+ }
2349
+
2350
+ .mint-topbar__tail {
2351
+ flex-shrink: 0;
2352
+ }
2353
+
2354
+ /* The deprecated #actions slot keeps a fixed width, so its content cannot push the bar. */
2355
+ .mint-topbar__legacy-actions {
2356
+ display: inline-flex;
2357
+ align-items: center;
2358
+ max-width: 16rem;
2359
+ overflow: hidden;
2360
+ }
2361
+
2362
+ /* Below 1024px of bar width: row 1 is identity + tail, row 2 the pills + context.
2363
+ Row 1 never holds more than the identity, so the tail never moves. */
2364
+ @container mint-topbar (max-width: 1023.98px) {
2365
+ .mint-topbar__container--stackable {
2366
+ /* The pills keep their width while it fits; the context group takes the rest and its experiment
2367
+ name truncates. On a bar narrower than the pills they overflow their cell, never the tail. */
2368
+ grid-template-columns: minmax(0, max-content) minmax(0, 1fr) auto;
2369
+ grid-template-areas:
2370
+ "start start tail"
2371
+ "center context context";
2372
+ row-gap: 0.375rem;
2373
+ }
2374
+
2375
+ .mint-topbar__container--stackable .mint-topbar__start { grid-area: start; }
2376
+ .mint-topbar__container--stackable .mint-topbar__right { display: contents; }
2377
+ .mint-topbar__container--stackable .mint-topbar__tail { grid-area: tail; }
2378
+
2379
+ .mint-topbar__container--stackable .mint-topbar__center {
2380
+ grid-area: center;
2381
+ justify-content: flex-start;
2382
+ }
2383
+
2384
+ .mint-topbar__container--stackable .mint-topbar__context {
2385
+ /* Stretch, not justify-self: end, which would size the group to its nowrap min-content. */
2386
+ grid-area: context;
2387
+ justify-content: flex-end;
2388
+ }
2389
+ }
2390
+
2334
2391
  /* Logo styles */
2335
2392
  .mint-topbar__logo {
2336
2393
  display: flex;
@@ -2430,11 +2487,13 @@ button, input, select, textarea {
2430
2487
  white-space: nowrap;
2431
2488
  }
2432
2489
 
2433
- /* The settings button has the IconButton ghost look: 32px, --radius-md,
2434
- 16px icon, neutral ink, offset focus ring. */
2435
- .mint-topbar__settings-btn {
2490
+ /* The settings button, plugin icon buttons and the drawer button have the
2491
+ IconButton ghost look: 32px, --radius-md, 16px icon, neutral ink, offset focus ring. */
2492
+ .mint-topbar__settings-btn,
2493
+ .mint-topbar__icon-btn {
2436
2494
  position: relative;
2437
2495
  display: inline-flex;
2496
+ flex-shrink: 0;
2438
2497
  align-items: center;
2439
2498
  justify-content: center;
2440
2499
  width: 2rem;
@@ -2449,23 +2508,62 @@ button, input, select, textarea {
2449
2508
  transition: background-color var(--mint-transition), color var(--mint-transition);
2450
2509
  }
2451
2510
 
2452
- .mint-topbar__settings-btn:hover {
2511
+ .mint-topbar__settings-btn:hover,
2512
+ .mint-topbar__icon-btn:hover:not(:disabled) {
2453
2513
  background: var(--bg-hover);
2454
2514
  color: var(--text-primary);
2455
2515
  }
2456
2516
 
2457
- .mint-topbar__settings-btn:focus-visible {
2517
+ .mint-topbar__settings-btn:focus-visible,
2518
+ .mint-topbar__icon-btn:focus-visible {
2458
2519
  outline: none;
2459
2520
  box-shadow: var(--focus-ring-offset);
2460
2521
  }
2461
2522
 
2462
- .mint-topbar__settings-icon {
2523
+ .mint-topbar__icon-btn:disabled {
2524
+ cursor: not-allowed;
2525
+ opacity: 0.5;
2526
+ }
2527
+
2528
+ .mint-topbar__settings-icon,
2529
+ .mint-topbar__icon-btn-icon {
2463
2530
  width: 1rem;
2464
2531
  height: 1rem;
2465
2532
  }
2466
2533
 
2534
+ /* Status dot of a plugin icon button (TopBarAction.dot). */
2535
+ .mint-topbar__icon-btn-dot {
2536
+ position: absolute;
2537
+ top: 0.3125rem;
2538
+ right: 0.3125rem;
2539
+ width: 0.4375rem;
2540
+ height: 0.4375rem;
2541
+ border-radius: 50%;
2542
+ box-shadow: 0 0 0 2px var(--bg-secondary);
2543
+ background: var(--text-muted);
2544
+ }
2545
+
2546
+ .mint-topbar__icon-btn-dot--primary,
2547
+ .mint-topbar__icon-btn-dot--cta { background: var(--color-primary); }
2548
+ .mint-topbar__icon-btn-dot--success { background: var(--mint-success); }
2549
+ .mint-topbar__icon-btn-dot--warning { background: var(--mint-warning); }
2550
+ .mint-topbar__icon-btn-dot--error { background: var(--mint-error); }
2551
+ .mint-topbar__icon-btn-dot--info { background: var(--mint-info); }
2552
+
2553
+ /* The drawer button shows only while the AppLayout sidebar is a drawer. */
2554
+ .mint-topbar__sidebar-toggle {
2555
+ display: none;
2556
+ }
2557
+
2558
+ @media (max-width: 1023.98px) {
2559
+ .mint-topbar__sidebar-toggle {
2560
+ display: inline-flex;
2561
+ }
2562
+ }
2563
+
2467
2564
  @media (prefers-reduced-motion: reduce) {
2468
- .mint-topbar__settings-btn {
2565
+ .mint-topbar__settings-btn,
2566
+ .mint-topbar__icon-btn {
2469
2567
  transition: none;
2470
2568
  }
2471
2569
  }
@@ -2647,6 +2745,32 @@ button, input, select, textarea {
2647
2745
  clip-path: inset(50%);
2648
2746
  white-space: nowrap;
2649
2747
  }
2748
+
2749
+ /* ─── Labels or icons, by fit ───
2750
+ Save and Jobs show their words while the content fits; AppTopBar.compact.ts
2751
+ sets --compact when it does not (a name is cut, the experiment chip is
2752
+ squeezed or a group overflows), and they keep only their icons. Plugin
2753
+ buttons with an icon are always icon-only. Accessible names and tooltips
2754
+ keep the words. */
2755
+ .mint-topbar--compact .mint-experiment-popover__save {
2756
+ width: 32px;
2757
+ padding: 0;
2758
+ justify-content: center;
2759
+ }
2760
+
2761
+ .mint-topbar--compact .mint-experiment-popover__save-label,
2762
+ .mint-topbar--compact .mint-topbar__job-label {
2763
+ display: none;
2764
+ }
2765
+
2766
+ .mint-topbar--compact .mint-topbar__job--idle {
2767
+ padding-inline: 0.5rem;
2768
+ }
2769
+
2770
+ /* One total width cap for the experiment chip, code and chevron included. */
2771
+ .mint-topbar .mint-experiment-popover__trigger {
2772
+ max-width: 16rem;
2773
+ }
2650
2774
  /* BaseButton Component Styles */
2651
2775
 
2652
2776
  .mint-button {
@@ -169,6 +169,7 @@ export type PillNavItemInput = (Omit<PillNavItem, 'children'> & {
169
169
  export interface PageSelectorItem {
170
170
  id: string;
171
171
  label: string;
172
+ /** A Lucide icon name (`'activity'`, `'flask-conical'`) or a plugin icon (path, data URL, `mint-icon` JSON). Without one the page shows its first letter. */
172
173
  icon?: string;
173
174
  hint?: string;
174
175
  to?: string;
@@ -186,12 +187,31 @@ export interface PluginWorkspaceTopBarSpec {
186
187
  logo?: boolean;
187
188
  /** Centered pill navigation for the local modes of the current route (bind `v-model:pill`). */
188
189
  pills?: PillNavItemInput[];
189
- /** Show the theme toggle. */
190
+ /** @deprecated Ignored: the theme toggle always shows. Removed in 2.0. */
190
191
  themeToggle?: boolean;
191
- /** Settings button and modal; `false` hides the button. A getter can switch it per user. */
192
+ /**
193
+ * Settings modal of the always-present settings button. `false` (or a getter that returns it)
194
+ * gives the modal only its Appearance tab; it no longer hides the button.
195
+ */
192
196
  settings?: import('vue').MaybeRefOrGetter<false | TopBarSettingsConfig>;
193
197
  /** Standalone badge text when the plugin runs outside the platform; `false` hides it. */
194
198
  standaloneLabel?: false | string;
199
+ /** Plugin buttons, before the theme and settings buttons. The first two show; the rest go into a More menu. */
200
+ actions?: TopBarAction[];
201
+ }
202
+ /** One plugin button of the top bar. With `icon` it is an icon button and `label` is its accessible name and tooltip. */
203
+ export interface TopBarAction {
204
+ id: string;
205
+ label: string;
206
+ /** A Lucide icon name, such as `'database'`. */
207
+ icon?: string;
208
+ /** A small status dot on the button. */
209
+ dot?: Tone;
210
+ /** Tooltip; defaults to `label`. */
211
+ title?: string;
212
+ loading?: boolean;
213
+ disabled?: boolean;
214
+ onSelect: () => void;
195
215
  }
196
216
  /** Sidebar part of a PluginWorkspaceView spec; also the `:spec` of AppSidebar. */
197
217
  export interface PluginWorkspaceSidebarSpec {
@@ -1,4 +1,4 @@
1
- export type { Tone, ContainerDirection, ButtonVariant, ButtonSize, ActionMenuItem, InputType, ModalSize, ModalVariant, ModalLayout, ModalTab, Toast, ToastAction, ToastOptions, OptionPrimitive, SelectOption, SelectOptionInput, FormFieldProps, SectionCardAccent, SectionCardDivider, SidebarToolSection, SidebarToolSectionAction, CollapsibleState, TopBarVariant, TopBarSettingsConfig, PillNavOption, PillNavOptionInput, PillNavItem, PillNavItemInput, PageSelectorItem, PageSelectorItemInput, PluginWorkspaceTopBarSpec, PluginWorkspaceSidebarSpec, PluginWorkspaceViewSpec, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, WellClassValue, WellClassResolver, WellStyleResolver, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellSampleDropData, WellSampleDropContext, WellSampleDropParser, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, PlateEditorClearConfirm, WellPlateSpec, PlateEditorSpec, SampleType, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, FileUploaderMode, ChartLegendItem, SegmentedControlVariant, SegmentedControlSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, DataFrameSpec, SpinnerSize, DividerSpacing, ProgressSize, AvatarSize, EmptyStateSize, BreadcrumbItem, BreadcrumbItemInput, TooltipPosition, SettingsTab, SettingsTabInput, SettingsModalLayout, SettingsGroup, SettingsModalSchema, SettingsUserType, SettingsAudience, SettingsAudienceInput, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimeSlotDisabledFn, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, SummarySectionItem, SummarySection, SummaryData, ResourceStatus, ResourceSpec, MoleculeData, ExperimentStatus, DatePreset, ExperimentSortField, ExperimentTypeOption, ExperimentSummary, ExperimentListResponse, ExperimentFilters, TreeNodeType, BadgeVariant, TreeNode, } from './components';
1
+ export type { Tone, ContainerDirection, ButtonVariant, ButtonSize, ActionMenuItem, InputType, ModalSize, ModalVariant, ModalLayout, ModalTab, Toast, ToastAction, ToastOptions, OptionPrimitive, SelectOption, SelectOptionInput, FormFieldProps, SectionCardAccent, SectionCardDivider, SidebarToolSection, SidebarToolSectionAction, CollapsibleState, TopBarVariant, TopBarSettingsConfig, PillNavOption, PillNavOptionInput, PillNavItem, PillNavItemInput, PageSelectorItem, PageSelectorItemInput, PluginWorkspaceTopBarSpec, TopBarAction, PluginWorkspaceSidebarSpec, PluginWorkspaceViewSpec, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, WellClassValue, WellClassResolver, WellStyleResolver, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellSampleDropData, WellSampleDropContext, WellSampleDropParser, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, PlateEditorClearConfirm, WellPlateSpec, PlateEditorSpec, SampleType, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, FileUploaderMode, ChartLegendItem, SegmentedControlVariant, SegmentedControlSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, DataFrameSpec, SpinnerSize, DividerSpacing, ProgressSize, AvatarSize, EmptyStateSize, BreadcrumbItem, BreadcrumbItemInput, TooltipPosition, SettingsTab, SettingsTabInput, SettingsModalLayout, SettingsGroup, SettingsModalSchema, SettingsUserType, SettingsAudience, SettingsAudienceInput, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimeSlotDisabledFn, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, SummarySectionItem, SummarySection, SummaryData, ResourceStatus, ResourceSpec, MoleculeData, ExperimentStatus, DatePreset, ExperimentSortField, ExperimentTypeOption, ExperimentSummary, ExperimentListResponse, ExperimentFilters, TreeNodeType, BadgeVariant, TreeNode, } from './components';
2
2
  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';
@@ -345,6 +345,15 @@ var _hoisted_29 = {
345
345
  };
346
346
  /** Open modals, oldest first; shared by every BaseModal instance. */
347
347
  var openModals = [];
348
+ /** Body overflow from before the first modal opened, restored when the last one closes. */
349
+ var bodyOverflowBeforeLock = "";
350
+ /** Body scroll follows the stack: locked while any modal is open. */
351
+ function syncBodyScrollLock(wasEmpty) {
352
+ if (wasEmpty && openModals.length > 0) {
353
+ bodyOverflowBeforeLock = document.body.style.overflow;
354
+ document.body.style.overflow = "hidden";
355
+ } else if (!wasEmpty && openModals.length === 0) document.body.style.overflow = bodyOverflowBeforeLock;
356
+ }
348
357
  //#endregion
349
358
  //#region src/components/BaseModal.vue
350
359
  var BaseModal_default = /* @__PURE__ */ defineComponent({
@@ -417,14 +426,13 @@ var BaseModal_default = /* @__PURE__ */ defineComponent({
417
426
  containerRef,
418
427
  active: toRef(props, "open")
419
428
  });
420
- watch(() => props.open, (isOpen) => {
421
- document.body.style.overflow = isOpen ? "hidden" : "";
422
- });
423
429
  const self = {};
424
430
  watch(() => props.open, (isOpen) => {
431
+ const wasEmpty = openModals.length === 0;
425
432
  const index = openModals.indexOf(self);
426
433
  if (isOpen && index === -1) openModals.push(self);
427
434
  if (!isOpen && index !== -1) openModals.splice(index, 1);
435
+ syncBodyScrollLock(wasEmpty);
428
436
  }, { immediate: true });
429
437
  function handleEscapeKeydown(event) {
430
438
  if (event.key === "Escape" && !event.defaultPrevented && props.closeOnEscape && props.open && openModals[openModals.length - 1] === self) close();
@@ -440,9 +448,10 @@ var BaseModal_default = /* @__PURE__ */ defineComponent({
440
448
  }
441
449
  useEventListener(() => document, "keydown", handleEscapeKeydown);
442
450
  onUnmounted(() => {
443
- document.body.style.overflow = "";
451
+ const wasEmpty = openModals.length === 0;
444
452
  const index = openModals.indexOf(self);
445
453
  if (index !== -1) openModals.splice(index, 1);
454
+ syncBodyScrollLock(wasEmpty);
446
455
  });
447
456
  return (_ctx, _cache) => {
448
457
  return openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: `modal-${__props.variant}` }, {
@@ -605,4 +614,4 @@ function useDropdownState(options = {}) {
605
614
  //#endregion
606
615
  export { BaseButton_default as a, useEventListener as i, BaseModal_default as n, __exportAll as o, useFocusTrap as r, useDropdownState as t };
607
616
 
608
- //# sourceMappingURL=useDropdownState-uFIz6Yv8.js.map
617
+ //# sourceMappingURL=useDropdownState-CcBzUYZ6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDropdownState-CcBzUYZ6.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","../src/composables/useDropdownState.ts"],"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 { Comment, Fragment, Text, computed, useSlots, type Component, type VNode } 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\n// A text-only label gets its own span so the stylesheet can centre the cap height.\n// Element children are left as flex items, so their gap and alignment do not change.\nfunction isTextNode(node: VNode): boolean {\n if (node.type === Text || node.type === Comment) return true\n return node.type === Fragment && Array.isArray(node.children)\n && (node.children as VNode[]).every(isTextNode)\n}\n\nfunction hasTextLabel(): boolean {\n const nodes = slots.default?.()\n return !!nodes && nodes.length > 0 && nodes.every(isTextNode)\n}\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 <span v-if=\"hasTextLabel()\" class=\"mint-button__label\"><slot /></span>\n <slot v-else />\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 { Comment, Fragment, Text, computed, useSlots, type Component, type VNode } 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\n// A text-only label gets its own span so the stylesheet can centre the cap height.\n// Element children are left as flex items, so their gap and alignment do not change.\nfunction isTextNode(node: VNode): boolean {\n if (node.type === Text || node.type === Comment) return true\n return node.type === Fragment && Array.isArray(node.children)\n && (node.children as VNode[]).every(isTextNode)\n}\n\nfunction hasTextLabel(): boolean {\n const nodes = slots.default?.()\n return !!nodes && nodes.length > 0 && nodes.every(isTextNode)\n}\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 <span v-if=\"hasTextLabel()\" class=\"mint-button__label\"><slot /></span>\n <slot v-else />\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/** Body overflow from before the first modal opened, restored when the last one closes. */\nlet bodyOverflowBeforeLock = ''\n\n/** Body scroll follows the stack: locked while any modal is open. */\nfunction syncBodyScrollLock(wasEmpty: boolean) {\n if (wasEmpty && openModals.length > 0) {\n bodyOverflowBeforeLock = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n } else if (!wasEmpty && openModals.length === 0) {\n document.body.style.overflow = bodyOverflowBeforeLock\n }\n}\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\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const wasEmpty = openModals.length === 0\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n syncBodyScrollLock(wasEmpty)\n}, { immediate: true })\n\n// A control inside the modal that handles Escape (an open select) prevents the default first.\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && !event.defaultPrevented && 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 const wasEmpty = openModals.length === 0\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n syncBodyScrollLock(wasEmpty)\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/** Body overflow from before the first modal opened, restored when the last one closes. */\nlet bodyOverflowBeforeLock = ''\n\n/** Body scroll follows the stack: locked while any modal is open. */\nfunction syncBodyScrollLock(wasEmpty: boolean) {\n if (wasEmpty && openModals.length > 0) {\n bodyOverflowBeforeLock = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n } else if (!wasEmpty && openModals.length === 0) {\n document.body.style.overflow = bodyOverflowBeforeLock\n }\n}\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\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const wasEmpty = openModals.length === 0\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n syncBodyScrollLock(wasEmpty)\n}, { immediate: true })\n\n// A control inside the modal that handles Escape (an open select) prevents the default first.\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && !event.defaultPrevented && 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 const wasEmpty = openModals.length === 0\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n syncBodyScrollLock(wasEmpty)\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","import { nextTick, ref, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseDropdownStateOptions {\n closeOnOutsideClick?: boolean\n closeOnEscape?: boolean\n /** Close the panel when the page scrolls or the viewport resizes. Default `false`. */\n closeOnScroll?: boolean\n insideRefs?: Array<Ref<HTMLElement | null>>\n /**\n * Element that counts as \"inside\" for outside-click closing, typically a\n * `useTemplateRef()`. Without one, bind the returned `rootRef` instead.\n */\n rootRef?: Ref<HTMLElement | null>\n /**\n * Element focus returns to when the panel closes with `close(true)` (Escape).\n * Pass one when the trigger lives outside `rootRef`; otherwise bind the\n * returned `triggerRef` to the trigger element.\n */\n triggerRef?: Ref<HTMLElement | null>\n onOpen?: () => void\n onClose?: () => void\n}\n\nexport interface UseDropdownStateReturn {\n isOpen: Ref<boolean>\n rootRef: Ref<HTMLElement | null>\n /** Bind to the trigger element so Escape can return focus to it. */\n triggerRef: Ref<HTMLElement | null>\n open: () => void\n /** Closes the panel; `returnFocus` moves focus back to `triggerRef`. */\n close: (returnFocus?: boolean) => void\n toggle: () => void\n handleClickOutside: (event: MouseEvent) => void\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * Shared disclosure state for dropdown-style SDK components: open/close state,\n * outside-click and Escape closing, optional scroll/resize closing, and focus\n * return to the trigger. `close(returnFocus)` mirrors `useMenuKeyboard`'s\n * contract, so the two compose directly.\n */\nexport function useDropdownState(options: UseDropdownStateOptions = {}): UseDropdownStateReturn {\n const isOpen = ref(false)\n const rootRef = options.rootRef ?? ref<HTMLElement | null>(null)\n const triggerRef = options.triggerRef ?? ref<HTMLElement | null>(null)\n const closeOnOutsideClick = options.closeOnOutsideClick ?? true\n const closeOnEscape = options.closeOnEscape ?? true\n const closeOnScroll = options.closeOnScroll ?? false\n\n function open(): void {\n if (isOpen.value) return\n isOpen.value = true\n options.onOpen?.()\n }\n\n function close(returnFocus = false): void {\n if (!isOpen.value) return\n isOpen.value = false\n options.onClose?.()\n if (returnFocus) {\n void nextTick(() => triggerRef.value?.focus())\n }\n }\n\n function toggle(): void {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n function handleClickOutside(event: MouseEvent): void {\n if (!closeOnOutsideClick || !isOpen.value || !rootRef.value) return\n const target = event.target\n if (\n target instanceof Node &&\n !rootRef.value.contains(target) &&\n !options.insideRefs?.some(ref => ref.value?.contains(target))\n ) {\n close()\n }\n }\n\n function handleKeydown(event: KeyboardEvent): void {\n if (closeOnEscape && event.key === 'Escape') {\n close(true)\n }\n }\n\n function handleViewportChange(): void {\n if (isOpen.value) close()\n }\n\n if (closeOnOutsideClick) {\n useEventListener(() => document, 'click', handleClickOutside)\n }\n if (closeOnEscape) {\n useEventListener(() => document, 'keydown', handleKeydown)\n }\n if (closeOnScroll) {\n useEventListener(() => window, 'scroll', handleViewportChange, true)\n useEventListener(() => window, 'resize', handleViewportChange)\n }\n\n return {\n isOpen,\n rootRef,\n triggerRef,\n open,\n close,\n toggle,\n handleClickOutside,\n handleKeydown,\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { o as useApi, r as readErrorMessage } from "./experiment-DyO54FQB.js";
2
- import { _ as APP_EXPERIMENT_KEY, a as parseExperimentId, t as isRecord } from "./records-BAymyHAn.js";
3
- import { t as useRequest } from "./useRequest-D9-3BS-3.js";
2
+ import { _ as APP_EXPERIMENT_KEY, a as parseExperimentId, t as isRecord } from "./records-GtiVMlTQ.js";
3
+ import { t as useRequest } from "./useRequest-CXyPw3eh.js";
4
4
  import { computed, inject, ref, shallowRef, toValue, watch } from "vue";
5
5
  //#region src/composables/experimentDesignData.ts
6
6
  function isPlatformDesignDataResponse(value) {
@@ -405,4 +405,4 @@ function useExperimentSamples(options = {}) {
405
405
  //#endregion
406
406
  export { readTableFileAsCsv as a, useExperimentData as c, unwrapExperimentDesignData as d, readFileAsText as i, extractSampleNamesFromDesignData as l, detectDelimiter as n, useFileImport as o, parseDelimitedText as r, validateImportFile as s, useExperimentSamples as t, extractSampleOptionsFromDesignData as u };
407
407
 
408
- //# sourceMappingURL=useExperimentSamples-DEDAKa2E.js.map
408
+ //# sourceMappingURL=useExperimentSamples-CpNXvpUn.js.map