@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.
- package/dist/{AlertBox-CexONPhA.js → AlertBox-Cai0w7gF.js} +3 -3
- package/dist/{AlertBox-CexONPhA.js.map → AlertBox-Cai0w7gF.js.map} +1 -1
- package/dist/{AppSidebar-FxlF5_dI.js → AppSidebar-C1DT4nsZ.js} +351 -90
- package/dist/AppSidebar-C1DT4nsZ.js.map +1 -0
- package/dist/{ConfirmDialog-D9QXFpsy.js → ConfirmDialog-BjFsOpBe.js} +2 -2
- package/dist/{ConfirmDialog-D9QXFpsy.js.map → ConfirmDialog-BjFsOpBe.js.map} +1 -1
- package/dist/{ExperimentPopover-Bbd6RaoH.js → ExperimentPopover-DYy_s0kI.js} +25 -37
- package/dist/ExperimentPopover-DYy_s0kI.js.map +1 -0
- package/dist/{ExperimentSelectorModal-CUkKmgfr.js → ExperimentSelectorModal-Bfh5bdkv.js} +5 -5
- package/dist/{ExperimentSelectorModal-CUkKmgfr.js.map → ExperimentSelectorModal-Bfh5bdkv.js.map} +1 -1
- package/dist/{SegmentedControl-C-sckoJZ.js → SegmentedControl-B8KgyOjd.js} +2 -2
- package/dist/{SegmentedControl-C-sckoJZ.js.map → SegmentedControl-B8KgyOjd.js.map} +1 -1
- package/dist/{SettingsModal-BIC0dAYc.js → SettingsModal-DPNblTe9.js} +7 -7
- package/dist/{SettingsModal-BIC0dAYc.js.map → SettingsModal-DPNblTe9.js.map} +1 -1
- package/dist/__tests__/components/AppTopBarCompact.test.d.ts +1 -0
- package/dist/__tests__/components/AppTopBarCompactReset.test.d.ts +1 -0
- package/dist/__tests__/components/AutoGroupModal.experimentLoad.test.d.ts +1 -0
- package/dist/components/AppTopBar.compact.d.ts +5 -0
- package/dist/components/AppTopBar.vue.d.ts +17 -17
- package/dist/components/PluginWorkspaceView.vue.d.ts +4 -0
- package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -2
- package/dist/components/internal/LucideIconInternal.vue.d.ts +17 -0
- package/dist/composables/appLayoutSidebar.d.ts +9 -0
- package/dist/composables/useVersionedSave.d.ts +5 -2
- package/dist/{controlSchemaModel-C_XqpkgE.js → controlSchemaModel-BtFNZj8t.js} +2 -2
- package/dist/{controlSchemaModel-C_XqpkgE.js.map → controlSchemaModel-BtFNZj8t.js.map} +1 -1
- package/dist/{data-CfY7o8QC.js → data-CJztFns8.js} +31 -15
- package/dist/{data-CfY7o8QC.js.map → data-CJztFns8.js.map} +1 -1
- package/dist/data.js +8 -8
- package/dist/{experimentStatus-DCn2QKG7.js → experimentStatus-Deokk7Br.js} +2 -2
- package/dist/{experimentStatus-DCn2QKG7.js.map → experimentStatus-Deokk7Br.js.map} +1 -1
- package/dist/index.js +14 -14
- package/dist/{install-QF3Sh82O.js → install-9FkKs0iW.js} +14 -15
- package/dist/{install-QF3Sh82O.js.map → install-9FkKs0iW.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-BcX5JBSY.js → lab-BYhb_cJI.js} +22 -14
- package/dist/lab-BYhb_cJI.js.map +1 -0
- package/dist/lab.js +4 -4
- package/dist/{records-BAymyHAn.js → records-GtiVMlTQ.js} +198 -62
- package/dist/records-GtiVMlTQ.js.map +1 -0
- package/dist/{runtime-DngeJtdq.js → runtime-DcMsvlaS.js} +29 -12
- package/dist/runtime-DcMsvlaS.js.map +1 -0
- package/dist/runtime.js +6 -6
- package/dist/{shell-CWZi97nW.js → shell-XZYkAZS_.js} +5 -5
- package/dist/{shell-CWZi97nW.js.map → shell-XZYkAZS_.js.map} +1 -1
- package/dist/shell.js +5 -5
- package/dist/styles.css +136 -12
- package/dist/types/components.d.ts +22 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/{useDropdownState-uFIz6Yv8.js → useDropdownState-CcBzUYZ6.js} +14 -5
- package/dist/useDropdownState-CcBzUYZ6.js.map +1 -0
- package/dist/{useExperimentSamples-DEDAKa2E.js → useExperimentSamples-CpNXvpUn.js} +3 -3
- package/dist/{useExperimentSamples-DEDAKa2E.js.map → useExperimentSamples-CpNXvpUn.js.map} +1 -1
- package/dist/{useListReorder-W1bzK_bo.js → useListReorder-Bp4EAI2w.js} +3 -3
- package/dist/{useListReorder-W1bzK_bo.js.map → useListReorder-Bp4EAI2w.js.map} +1 -1
- package/dist/{useRackEditor-Bmtuo0aj.js → useRackEditor-i2bdPUFf.js} +8 -8
- package/dist/{useRackEditor-Bmtuo0aj.js.map → useRackEditor-i2bdPUFf.js.map} +1 -1
- package/dist/{useRealtime-jOetF2mM.js → useRealtime-BLQEjbuq.js} +3 -3
- package/dist/{useRealtime-jOetF2mM.js.map → useRealtime-BLQEjbuq.js.map} +1 -1
- package/dist/useRequest-CXyPw3eh.js +76 -0
- package/dist/useRequest-CXyPw3eh.js.map +1 -0
- package/dist/utils/deprecation.d.ts +2 -0
- package/dist/utils/lucideIcon.d.ts +4 -0
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +102 -20
- package/src/__tests__/components/AppTopBarCompact.test.ts +65 -0
- package/src/__tests__/components/AppTopBarCompactReset.test.ts +24 -0
- package/src/__tests__/components/AutoGroupModal.experimentLoad.test.ts +58 -0
- package/src/__tests__/components/BaseModal.test.ts +33 -2
- package/src/__tests__/components/ExperimentPopover.test.ts +32 -0
- package/src/__tests__/components/PluginWorkspaceView.test.ts +1 -1
- package/src/__tests__/composables/useJobCenter.test.ts +35 -0
- package/src/__tests__/composables/useVersionedSave.test.ts +71 -6
- package/src/__tests__/styles/menusShellRefresh.test.ts +5 -0
- package/src/components/AppLayout.story.vue +5 -5
- package/src/components/AppLayout.vue +13 -1
- package/src/components/AppTopBar.compact.ts +60 -0
- package/src/components/AppTopBar.story.vue +39 -14
- package/src/components/AppTopBar.vue +222 -89
- package/src/components/BaseModal.vue +16 -5
- package/src/components/ExperimentPopover.story.vue +2 -2
- package/src/components/ExperimentPopover.vue +6 -22
- package/src/components/GeneratedPluginView.vue +0 -1
- package/src/components/PluginWorkspaceView.vue +8 -0
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +12 -0
- package/src/components/internal/AutoGroupModalInternal.vue +14 -3
- package/src/components/internal/LucideIconInternal.vue +23 -0
- package/src/composables/appLayoutSidebar.ts +11 -0
- package/src/composables/useJobCenter.ts +21 -1
- package/src/composables/usePluginWorkspace.ts +1 -1
- package/src/composables/useVersionedSave.ts +32 -7
- package/src/styles/components/app-layout.css +5 -0
- package/src/styles/components/app-top-bar.css +128 -8
- package/src/types/components.ts +23 -2
- package/src/types/index.ts +1 -0
- package/src/utils/deprecation.ts +8 -0
- package/src/utils/lucideIcon.ts +25 -0
- package/src/utils/lucideIconIndex.d.ts +2 -0
- package/dist/AppSidebar-FxlF5_dI.js.map +0 -1
- package/dist/ExperimentPopover-Bbd6RaoH.js.map +0 -1
- package/dist/lab-BcX5JBSY.js.map +0 -1
- package/dist/records-BAymyHAn.js.map +0 -1
- package/dist/runtime-DngeJtdq.js.map +0 -1
- package/dist/useDropdownState-uFIz6Yv8.js.map +0 -1
- package/dist/useRequest-D9-3BS-3.js +0 -215
- 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-
|
|
2
|
-
import {
|
|
3
|
-
import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-
|
|
4
|
-
import {
|
|
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-
|
|
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-
|
|
2
|
-
import {
|
|
3
|
-
import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-
|
|
4
|
-
import {
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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
|
|
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-
|
|
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
|
-
/**
|
|
190
|
+
/** @deprecated Ignored: the theme toggle always shows. Removed in 2.0. */
|
|
190
191
|
themeToggle?: boolean;
|
|
191
|
-
/**
|
|
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 {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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-
|
|
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-
|
|
3
|
-
import { t as useRequest } from "./useRequest-
|
|
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-
|
|
408
|
+
//# sourceMappingURL=useExperimentSamples-CpNXvpUn.js.map
|