@morscherlab/mint-sdk 1.5.0-beta.7 → 1.5.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/{AlertBox-CexONPhA.js → AlertBox-Cai0w7gF.js} +3 -3
  2. package/dist/{AlertBox-CexONPhA.js.map → AlertBox-Cai0w7gF.js.map} +1 -1
  3. package/dist/{AppSidebar-C4qQLHcH.js → AppSidebar-C-Vq5x4I.js} +361 -93
  4. package/dist/AppSidebar-C-Vq5x4I.js.map +1 -0
  5. package/dist/{ConfirmDialog-D9QXFpsy.js → ConfirmDialog-BjFsOpBe.js} +2 -2
  6. package/dist/{ConfirmDialog-D9QXFpsy.js.map → ConfirmDialog-BjFsOpBe.js.map} +1 -1
  7. package/dist/{ExperimentPopover-DyjoXwry.js → ExperimentPopover-DYy_s0kI.js} +21 -20
  8. package/dist/ExperimentPopover-DYy_s0kI.js.map +1 -0
  9. package/dist/{ExperimentSelectorModal-CUkKmgfr.js → ExperimentSelectorModal-Bfh5bdkv.js} +5 -5
  10. package/dist/{ExperimentSelectorModal-CUkKmgfr.js.map → ExperimentSelectorModal-Bfh5bdkv.js.map} +1 -1
  11. package/dist/{SegmentedControl-C-sckoJZ.js → SegmentedControl-B8KgyOjd.js} +2 -2
  12. package/dist/{SegmentedControl-C-sckoJZ.js.map → SegmentedControl-B8KgyOjd.js.map} +1 -1
  13. package/dist/{SettingsModal-B1ltysmg.js → SettingsModal-DwfrD1ER.js} +7 -7
  14. package/dist/{SettingsModal-B1ltysmg.js.map → SettingsModal-DwfrD1ER.js.map} +1 -1
  15. package/dist/__tests__/components/AppTopBarCompact.test.d.ts +1 -0
  16. package/dist/__tests__/components/AppTopBarCompactReset.test.d.ts +1 -0
  17. package/dist/__tests__/components/AutoGroupModal.experimentLoad.test.d.ts +1 -0
  18. package/dist/components/AppTopBar.compact.d.ts +5 -0
  19. package/dist/components/AppTopBar.vue.d.ts +17 -17
  20. package/dist/components/PluginWorkspaceView.vue.d.ts +4 -0
  21. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -2
  22. package/dist/components/internal/LucideIconInternal.vue.d.ts +17 -0
  23. package/dist/composables/appLayoutSidebar.d.ts +9 -0
  24. package/dist/composables/usePluginWorkspace.d.ts +2 -0
  25. package/dist/composables/useVersionedSave.d.ts +5 -2
  26. package/dist/{controlSchemaModel-C_XqpkgE.js → controlSchemaModel-BtFNZj8t.js} +2 -2
  27. package/dist/{controlSchemaModel-C_XqpkgE.js.map → controlSchemaModel-BtFNZj8t.js.map} +1 -1
  28. package/dist/{data-CgIcnf9D.js → data-CJztFns8.js} +31 -15
  29. package/dist/{data-CgIcnf9D.js.map → data-CJztFns8.js.map} +1 -1
  30. package/dist/data.js +8 -8
  31. package/dist/{experimentStatus-DCn2QKG7.js → experimentStatus-Deokk7Br.js} +2 -2
  32. package/dist/{experimentStatus-DCn2QKG7.js.map → experimentStatus-Deokk7Br.js.map} +1 -1
  33. package/dist/index.js +14 -14
  34. package/dist/{install-DmyjbTJ5.js → install-Bk02tJ5M.js} +14 -15
  35. package/dist/{install-DmyjbTJ5.js.map → install-Bk02tJ5M.js.map} +1 -1
  36. package/dist/install.js +1 -1
  37. package/dist/{lab-BcX5JBSY.js → lab-BYhb_cJI.js} +22 -14
  38. package/dist/lab-BYhb_cJI.js.map +1 -0
  39. package/dist/lab.js +4 -4
  40. package/dist/{records-BAymyHAn.js → records-GtiVMlTQ.js} +198 -62
  41. package/dist/records-GtiVMlTQ.js.map +1 -0
  42. package/dist/{runtime-CjfAxufu.js → runtime-aZPUPxoB.js} +40 -19
  43. package/dist/runtime-aZPUPxoB.js.map +1 -0
  44. package/dist/runtime.js +6 -6
  45. package/dist/{shell-XDqDu_UD.js → shell-Bk9mD4Lc.js} +5 -5
  46. package/dist/{shell-XDqDu_UD.js.map → shell-Bk9mD4Lc.js.map} +1 -1
  47. package/dist/shell.js +5 -5
  48. package/dist/styles.css +138 -13
  49. package/dist/types/components.d.ts +22 -2
  50. package/dist/types/index.d.ts +1 -1
  51. package/dist/{useDropdownState-uFIz6Yv8.js → useDropdownState-CcBzUYZ6.js} +14 -5
  52. package/dist/useDropdownState-CcBzUYZ6.js.map +1 -0
  53. package/dist/{useExperimentSamples-DEDAKa2E.js → useExperimentSamples-CpNXvpUn.js} +3 -3
  54. package/dist/{useExperimentSamples-DEDAKa2E.js.map → useExperimentSamples-CpNXvpUn.js.map} +1 -1
  55. package/dist/{useListReorder-W1bzK_bo.js → useListReorder-Bp4EAI2w.js} +3 -3
  56. package/dist/{useListReorder-W1bzK_bo.js.map → useListReorder-Bp4EAI2w.js.map} +1 -1
  57. package/dist/{useRackEditor-Bmtuo0aj.js → useRackEditor-i2bdPUFf.js} +8 -8
  58. package/dist/{useRackEditor-Bmtuo0aj.js.map → useRackEditor-i2bdPUFf.js.map} +1 -1
  59. package/dist/{useRealtime-jOetF2mM.js → useRealtime-BLQEjbuq.js} +3 -3
  60. package/dist/{useRealtime-jOetF2mM.js.map → useRealtime-BLQEjbuq.js.map} +1 -1
  61. package/dist/useRequest-CXyPw3eh.js +76 -0
  62. package/dist/useRequest-CXyPw3eh.js.map +1 -0
  63. package/dist/utils/deprecation.d.ts +2 -0
  64. package/dist/utils/lucideIcon.d.ts +4 -0
  65. package/package.json +1 -1
  66. package/src/__tests__/components/AppTopBar.test.ts +102 -20
  67. package/src/__tests__/components/AppTopBarCompact.test.ts +65 -0
  68. package/src/__tests__/components/AppTopBarCompactReset.test.ts +24 -0
  69. package/src/__tests__/components/AutoGroupModal.experimentLoad.test.ts +58 -0
  70. package/src/__tests__/components/BaseModal.test.ts +33 -2
  71. package/src/__tests__/components/PluginWorkspaceView.test.ts +20 -1
  72. package/src/__tests__/composables/useJobCenter.test.ts +35 -0
  73. package/src/__tests__/composables/useVersionedSave.test.ts +71 -6
  74. package/src/__tests__/styles/menusShellRefresh.test.ts +10 -0
  75. package/src/components/AppLayout.story.vue +5 -5
  76. package/src/components/AppLayout.vue +13 -1
  77. package/src/components/AppTopBar.compact.ts +60 -0
  78. package/src/components/AppTopBar.story.vue +39 -14
  79. package/src/components/AppTopBar.vue +222 -89
  80. package/src/components/BaseModal.vue +16 -5
  81. package/src/components/ExperimentPopover.vue +1 -1
  82. package/src/components/GeneratedPluginView.vue +0 -1
  83. package/src/components/PluginWorkspaceView.vue +10 -1
  84. package/src/components/internal/AppTopBarPageSelectorInternal.vue +12 -0
  85. package/src/components/internal/AutoGroupModalInternal.vue +14 -3
  86. package/src/components/internal/LucideIconInternal.vue +23 -0
  87. package/src/composables/appLayoutSidebar.ts +11 -0
  88. package/src/composables/useJobCenter.ts +21 -1
  89. package/src/composables/usePluginWorkspace.ts +15 -4
  90. package/src/composables/useVersionedSave.ts +32 -7
  91. package/src/styles/components/app-layout.css +5 -0
  92. package/src/styles/components/app-top-bar.css +130 -9
  93. package/src/types/components.ts +23 -2
  94. package/src/types/index.ts +1 -0
  95. package/src/utils/deprecation.ts +8 -0
  96. package/src/utils/lucideIcon.ts +25 -0
  97. package/src/utils/lucideIconIndex.d.ts +2 -0
  98. package/dist/AppSidebar-C4qQLHcH.js.map +0 -1
  99. package/dist/ExperimentPopover-DyjoXwry.js.map +0 -1
  100. package/dist/lab-BcX5JBSY.js.map +0 -1
  101. package/dist/records-BAymyHAn.js.map +0 -1
  102. package/dist/runtime-CjfAxufu.js.map +0 -1
  103. package/dist/useDropdownState-uFIz6Yv8.js.map +0 -1
  104. package/dist/useRequest-D9-3BS-3.js +0 -215
  105. package/dist/useRequest-D9-3BS-3.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"records-BAymyHAn.js","names":["$attrs","$attrs","$slots","$slots","$slots","$slots","$slots"],"sources":["../src/components/BaseInput.vue","../src/components/BaseInput.vue","../src/utils/options.ts","../src/composables/useFloatingPanel.ts","../src/composables/useSelectionLimit.ts","../src/composables/useListSelection.ts","../src/components/internal/SelectMultipleInternal.vue","../src/components/internal/SelectMultipleInternal.vue","../src/components/internal/SelectSearchableInternal.vue","../src/components/internal/SelectSearchableInternal.vue","../src/components/BaseSelect.vue","../src/components/BaseSelect.vue","../src/components/Tooltip.vue","../src/components/Tooltip.vue","../src/components/internal/CheckboxSwitchInternal.vue","../src/components/internal/CheckboxSwitchInternal.vue","../src/components/BaseCheckbox.vue","../src/components/BaseCheckbox.vue","../src/composables/useRovingFocus.ts","../src/components/EmptyState.vue","../src/components/EmptyState.vue","../src/components/FormField.vue","../src/components/FormField.vue","../src/utils/time.ts","../src/composables/useMenuKeyboard.ts","../src/components/FileUploader.vue","../src/components/FileUploader.vue","../src/composables/experiment-utils.ts","../src/composables/useAppExperiment.ts","../src/jobs.ts","../src/utils/pluginSecrets.ts","../src/components/SecretInput.vue","../src/components/SecretInput.vue","../src/components/TagsInput.vue","../src/components/TagsInput.vue","../src/composables/platformContextHelpers.ts","../src/components/Skeleton.vue","../src/components/Skeleton.vue","../src/components/internal/ResourcePickerListInternal.vue","../src/components/internal/ResourcePickerListInternal.vue","../src/utils/records.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a styled text `<input>`, or a `<textarea>` with `type=\"textarea\"`; size, invalid, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border (input only).\n * Numbers use NumberInput.\n *\n * @example\n * ```vue\n * <BaseInput v-model=\"name\" :invalid=\"!!nameError\" />\n * <BaseInput v-model=\"notes\" type=\"textarea\" :rows=\"4\" />\n * ```\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n maxlength?: number\n list?: string\n ariaDescribedby?: string\n /** Visible text lines (`textarea`). */\n rows?: number\n /** Resize handle (`textarea`). */\n resize?: 'none' | 'vertical' | 'horizontal' | 'both'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n rows: 3,\n resize: 'vertical',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => props.type !== 'textarea' && Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement | HTMLTextAreaElement).value)\n}\n</script>\n\n<template>\n <textarea\n v-if=\"type === 'textarea'\"\n v-bind=\"inputAttrs\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autofocus=\"autofocus\"\n :rows=\"rows\"\n :maxlength=\"maxlength\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-textarea',\n `mint-textarea--${size}`,\n `mint-textarea--resize-${resize}`,\n invalid ? 'mint-textarea--error' : '',\n disabled ? 'mint-textarea--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <div\n v-else-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n invalid ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n invalid ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled text `<input>`, or a `<textarea>` with `type=\"textarea\"`; size, invalid, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border (input only).\n * Numbers use NumberInput.\n *\n * @example\n * ```vue\n * <BaseInput v-model=\"name\" :invalid=\"!!nameError\" />\n * <BaseInput v-model=\"notes\" type=\"textarea\" :rows=\"4\" />\n * ```\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n maxlength?: number\n list?: string\n ariaDescribedby?: string\n /** Visible text lines (`textarea`). */\n rows?: number\n /** Resize handle (`textarea`). */\n resize?: 'none' | 'vertical' | 'horizontal' | 'both'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n rows: 3,\n resize: 'vertical',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => props.type !== 'textarea' && Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement | HTMLTextAreaElement).value)\n}\n</script>\n\n<template>\n <textarea\n v-if=\"type === 'textarea'\"\n v-bind=\"inputAttrs\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autofocus=\"autofocus\"\n :rows=\"rows\"\n :maxlength=\"maxlength\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-textarea',\n `mint-textarea--${size}`,\n `mint-textarea--resize-${resize}`,\n invalid ? 'mint-textarea--error' : '',\n disabled ? 'mint-textarea--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <div\n v-else-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n invalid ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :maxlength=\"maxlength\"\n :list=\"list\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n invalid ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","export type OptionLike<TValue extends string | number> = {\n value: TValue\n label: string\n}\n\nexport function normalizeOptionInput<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(option: TOption | TValue): TOption {\n if (typeof option === 'object') return option\n\n return {\n value: option,\n label: String(option),\n } as TOption\n}\n\nexport function findOptionByDomValue<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(options: TOption[], value: string): TOption | undefined {\n return options.find(option => String(option.value) === value)\n}\n","import {\n autoUpdate,\n computePosition,\n flip,\n hide,\n offset,\n shift,\n size,\n type Placement,\n type ReferenceElement,\n} from '@floating-ui/dom'\nimport { onScopeDispose, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'\n\n// Internal: not exported from the package entry points.\n\nexport interface UseFloatingPanelOptions {\n /** Default `'bottom-start'`. */\n placement?: MaybeRefOrGetter<Placement>\n /** Gap to the reference in px. Default 4. */\n offset?: number\n /** At least the reference width, at most 28rem (selects). */\n matchWidth?: boolean\n /** Re-place on scroll, resize and layout shift while open. Default `true`. */\n follow?: boolean\n}\n\nexport interface UseFloatingPanelReturn {\n /** Bind to the panel: `position: fixed`, `left`, `top`, and `visibility: hidden` while the reference is scrolled out of view. */\n style: Ref<Record<string, string>>\n /** The placement after flip, for arrows and transitions. */\n placement: Ref<Placement>\n update: () => Promise<void>\n}\n\n/**\n * Places `floating` next to `reference` with fixed positioning (offset, flip,\n * shift, size, hide). A fixed panel escapes the `overflow` of its ancestors (a\n * modal body) unless one of them has a transform, so it can stay in the DOM right\n * after its trigger: Tab order, focus traps and outside-click checks are those of\n * an in-place panel. The size middleware publishes the free height as\n * `--mint-floating-available-height`; a panel whose list scrolls caps its\n * `max-height` with it.\n */\nexport function useFloatingPanel(\n reference: MaybeRefOrGetter<ReferenceElement | null>,\n floating: Ref<HTMLElement | null>,\n open: Ref<boolean>,\n options: UseFloatingPanelOptions = {},\n): UseFloatingPanelReturn {\n const style = ref<Record<string, string>>({ position: 'fixed', left: '0px', top: '0px' })\n const placement = ref<Placement>(toValue(options.placement) ?? 'bottom-start')\n\n async function update(): Promise<void> {\n const referenceEl = toValue(reference)\n const floatingEl = floating.value\n if (!referenceEl || !floatingEl) return\n const result = await computePosition(referenceEl, floatingEl, {\n placement: toValue(options.placement) ?? 'bottom-start',\n strategy: 'fixed',\n middleware: [\n offset(options.offset ?? 4),\n flip(),\n shift({ padding: 8 }),\n size({\n padding: 8,\n // Written to the element, not the reactive style: floating-ui measures again right after.\n apply({ availableHeight, rects, elements }) {\n const target = elements.floating.style\n target.setProperty('--mint-floating-available-height', `${Math.max(0, availableHeight)}px`)\n if (options.matchWidth) {\n target.minWidth = `${rects.reference.width}px`\n target.maxWidth = '28rem'\n }\n },\n }),\n hide(),\n ],\n })\n const next: Record<string, string> = { position: 'fixed', left: `${result.x}px`, top: `${result.y}px` }\n // The trigger scrolled out of its scroll container: keep the panel open, but not floating detached.\n if (result.middlewareData.hide?.referenceHidden) next.visibility = 'hidden'\n // autoUpdate fires on every scroll; re-render only when the panel changes.\n const current = style.value\n if (current.left !== next.left || current.top !== next.top || current.visibility !== next.visibility) style.value = next\n placement.value = result.placement\n }\n\n let stop: (() => void) | undefined\n function release(): void {\n stop?.()\n stop = undefined\n }\n\n watch(\n [open, () => toValue(reference), floating],\n ([isOpen, referenceEl, floatingEl]) => {\n release()\n if (!isOpen || !referenceEl || !floatingEl) return\n if (options.follow ?? true) stop = autoUpdate(referenceEl, floatingEl, () => void update())\n else void update()\n },\n { flush: 'post', immediate: true },\n )\n onScopeDispose(release)\n\n return { style, placement, update }\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type SelectionLimitSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface UseSelectionLimitOptions {\n count: SelectionLimitSource<number>\n max?: SelectionLimitSource<number | null | undefined>\n}\n\nexport interface UseSelectionLimitReturn {\n count: ComputedRef<number>\n max: ComputedRef<number | undefined>\n isLimited: ComputedRef<boolean>\n isAtLimit: ComputedRef<boolean>\n canAddMore: ComputedRef<boolean>\n remaining: ComputedRef<number | undefined>\n canAdd: (amount?: number, fromCount?: number) => boolean\n}\n\n/** Shared cap logic for chip, tag, and multi-select controls. */\nexport function useSelectionLimit(options: UseSelectionLimitOptions): UseSelectionLimitReturn {\n const count = computed(() => Math.max(0, Math.floor(toValue(options.count) || 0)))\n const max = computed(() => normalizeMax(toValue(options.max)))\n const isLimited = computed(() => max.value !== undefined)\n const remaining = computed(() => {\n if (max.value === undefined) return undefined\n return Math.max(0, max.value - count.value)\n })\n const isAtLimit = computed(() => remaining.value === 0)\n const canAddMore = computed(() => canAdd(1))\n\n function canAdd(amount = 1, fromCount = count.value): boolean {\n const normalizedAmount = Math.max(0, Math.floor(amount))\n const normalizedCount = Math.max(0, Math.floor(fromCount))\n if (max.value === undefined) return true\n return normalizedCount + normalizedAmount <= max.value\n }\n\n return {\n count,\n max,\n isLimited,\n isAtLimit,\n canAddMore,\n remaining,\n canAdd,\n }\n}\n\nfunction normalizeMax(value: number | null | undefined): number | undefined {\n if (value === null || value === undefined || !Number.isFinite(value)) return undefined\n return Math.max(0, Math.floor(value))\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport { useSelectionLimit, type SelectionLimitSource } from './useSelectionLimit'\n\nexport type ListSelectionValue = string | number\n\nexport type ListSelectionSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type WidenListSelectionValue<TValue extends ListSelectionValue> =\n TValue extends string ? string : TValue extends number ? number : TValue\n\nexport interface UseListSelectionOptions<\n TItem,\n TValue extends ListSelectionValue = ListSelectionValue,\n> {\n selected: ListSelectionSource<readonly TValue[]>\n items?: ListSelectionSource<readonly TItem[]>\n getValue?: (item: TItem) => TValue\n disabled?: ListSelectionSource<boolean | null | undefined>\n max?: SelectionLimitSource<number | null | undefined>\n}\n\nexport interface UseListSelectionReturn<TValue extends ListSelectionValue = ListSelectionValue> {\n selectedValues: ComputedRef<TValue[]>\n selectedSet: ComputedRef<Set<TValue>>\n itemValues: ComputedRef<TValue[]>\n selectedCount: ComputedRef<number>\n itemCount: ComputedRef<number>\n isAllSelected: ComputedRef<boolean>\n isLimited: ComputedRef<boolean>\n isAtLimit: ComputedRef<boolean>\n canAddMore: ComputedRef<boolean>\n remaining: ComputedRef<number | undefined>\n isSelected: (value: TValue) => boolean\n isFullySelected: (values: readonly TValue[]) => boolean\n isPartiallySelected: (values: readonly TValue[]) => boolean\n selectValues: (values: readonly TValue[]) => TValue[]\n toggleValue: (value: TValue) => TValue[]\n toggleValues: (values: readonly TValue[]) => TValue[]\n selectAll: () => TValue[]\n toggleAll: () => TValue[]\n clear: () => TValue[]\n}\n\n/** Shared list-selection state for checkbox lists, sample selectors, and chip selectors. */\nexport function useListSelection<\n TItem = ListSelectionValue,\n TValue extends ListSelectionValue = TItem extends ListSelectionValue ? TItem : ListSelectionValue,\n>(options: UseListSelectionOptions<TItem, TValue>): UseListSelectionReturn<WidenListSelectionValue<TValue>> {\n type ResolvedValue = WidenListSelectionValue<TValue>\n\n const disabled = computed(() => toValue(options.disabled) ?? false)\n const selectedValues = computed<ResolvedValue[]>(() => [...toValue(options.selected)] as ResolvedValue[])\n const selectedSet = computed(() => new Set(selectedValues.value))\n const itemValues = computed<ResolvedValue[]>(() => {\n const items = toValue(options.items) ?? []\n return items.map(item => getItemValue(item, options.getValue) as ResolvedValue)\n })\n\n const selectedCount = computed(() => selectedValues.value.length)\n const itemCount = computed(() => itemValues.value.length)\n const isAllSelected = computed(() => (\n itemValues.value.length > 0 && itemValues.value.every(value => selectedSet.value.has(value))\n ))\n const selectionLimit = useSelectionLimit({\n count: selectedCount,\n max: options.max,\n })\n\n function isSelected(value: ResolvedValue): boolean {\n return selectedSet.value.has(value)\n }\n\n function isFullySelected(values: readonly ResolvedValue[]): boolean {\n return values.length > 0 && values.every(value => selectedSet.value.has(value))\n }\n\n function isPartiallySelected(values: readonly ResolvedValue[]): boolean {\n if (values.length === 0) return false\n const selected = values.filter(value => selectedSet.value.has(value)).length\n return selected > 0 && selected < values.length\n }\n\n function selectValues(values: readonly ResolvedValue[]): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n const missing = uniqueValues(values).filter(value => !selectedSet.value.has(value))\n if (!selectionLimit.canAdd(missing.length)) return selectedValues.value\n return [...selectedValues.value, ...missing]\n }\n\n function toggleValue(value: ResolvedValue): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n if (selectedSet.value.has(value)) {\n return selectedValues.value.filter(selected => selected !== value)\n }\n if (!selectionLimit.canAddMore.value) return selectedValues.value\n return [...selectedValues.value, value]\n }\n\n function toggleValues(values: readonly ResolvedValue[]): ResolvedValue[] {\n if (disabled.value) return selectedValues.value\n const unique = uniqueValues(values)\n if (isFullySelected(unique)) {\n const remove = new Set(unique)\n return selectedValues.value.filter(value => !remove.has(value))\n }\n return selectValues(unique)\n }\n\n function selectAll(): ResolvedValue[] {\n return selectValues(itemValues.value)\n }\n\n function toggleAll(): ResolvedValue[] {\n if (isAllSelected.value) return clear()\n return selectAll()\n }\n\n function clear(): ResolvedValue[] {\n return disabled.value ? selectedValues.value : []\n }\n\n return {\n selectedValues,\n selectedSet,\n itemValues,\n selectedCount,\n itemCount,\n isAllSelected,\n isLimited: selectionLimit.isLimited,\n isAtLimit: selectionLimit.isAtLimit,\n canAddMore: selectionLimit.canAddMore,\n remaining: selectionLimit.remaining,\n isSelected,\n isFullySelected,\n isPartiallySelected,\n selectValues,\n toggleValue,\n toggleValues,\n selectAll,\n toggleAll,\n clear,\n }\n}\n\nfunction getItemValue<TItem, TValue extends ListSelectionValue>(\n item: TItem,\n getValue: ((item: TItem) => TValue) | undefined,\n): TValue {\n return getValue ? getValue(item) : item as unknown as TValue\n}\n\nfunction uniqueValues<TValue extends ListSelectionValue>(values: readonly TValue[]): TValue[] {\n return [...new Set(values)]\n}\n","<script setup lang=\"ts\">\n/** BaseSelect with `multiple`: a field of removable chips that opens a filterable checkbox listbox, capped by `max`. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport { Check, ChevronDown, X } from 'lucide-vue-next'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { useFloatingPanel } from '../../composables/useFloatingPanel'\nimport { useListSelection } from '../../composables/useListSelection'\nimport { normalizeOptionInput } from '../../utils/options'\n\ntype MultiOption = SelectOption<OptionPrimitive>\n\ninterface Props {\n modelValue: OptionPrimitive[]\n options: SelectOptionInput[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n max?: number\n size?: 'sm' | 'md' | 'lg'\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select options...',\n disabled: false,\n invalid: false,\n max: undefined,\n size: 'md',\n ariaLabelledby: undefined,\n ariaDescribedby: undefined,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focusable field.\nconst attrs = useAttrs()\nconst fieldAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: OptionPrimitive[]]\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-multi-select-${id}`\nconst root = ref<HTMLElement | null>(null)\nconst field = ref<HTMLElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst panel = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\n\nconst normalizedOptions = computed<MultiOption[]>(() => props.options.map(normalizeOptionInput<OptionPrimitive, MultiOption>))\nconst selection = useListSelection({\n selected: () => props.modelValue,\n items: normalizedOptions,\n getValue: option => option.value,\n disabled: () => props.disabled,\n max: () => props.max,\n})\n\nconst chips = computed(() => props.modelValue.map(value => ({\n value,\n label: normalizedOptions.value.find(option => option.value === value)?.label ?? String(value),\n})))\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option => option.label.toLocaleLowerCase().includes(needle))\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction isUnavailable(option: MultiOption): boolean {\n return !!option.disabled || (!selection.isSelected(option.value) && !selection.canAddMore.value)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled || open.value) return\n query.value = ''\n open.value = true\n activeIndex.value = visibleOptions.value.length > 0 ? 0 : -1\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n field.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const count = visibleOptions.value.length\n if (count === 0) return\n const start = activeIndex.value < 0 ? (direction === 1 ? -1 : count) : activeIndex.value\n activeIndex.value = (start + direction + count) % count\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction toggle(option: MultiOption): void {\n if (props.disabled || isUnavailable(option)) return\n emit('update:modelValue', selection.toggleValue(option.value))\n}\n\nfunction remove(value: OptionPrimitive): void {\n if (props.disabled) return\n emit('update:modelValue', props.modelValue.filter(selected => selected !== value))\n}\n\nfunction handleFieldKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Enter' && event.key !== ' ' && event.key !== 'ArrowDown') return\n event.preventDefault()\n void openPanel()\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) toggle(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else if (event.key === 'Backspace' && query.value === '' && props.modelValue.length > 0) {\n remove(props.modelValue[props.modelValue.length - 1]!)\n } else return\n event.preventDefault()\n}\n\n// Fixed next to the field, so a modal body's overflow does not clip it; it stays in place in the DOM.\nconst { style: panelStyle } = useFloatingPanel(field, panel, open, { matchWidth: true })\n\nwatch(visibleOptions, options => { activeIndex.value = options.length > 0 ? 0 : -1 })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-multi-select', `mint-multi-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <div\n v-bind=\"fieldAttrs\"\n ref=\"field\"\n role=\"combobox\"\n :tabindex=\"disabled ? undefined : 0\"\n :class=\"[\n 'mint-multi-select__field',\n {\n 'mint-multi-select__field--open': open,\n 'mint-multi-select__field--error': invalid,\n 'mint-multi-select__field--disabled': disabled,\n },\n ]\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-disabled=\"disabled || undefined\"\n :aria-invalid=\"invalid || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown.self=\"handleFieldKeydown\"\n >\n <div class=\"mint-multi-select__chips\">\n <span v-for=\"chip in chips\" :key=\"String(chip.value)\" class=\"mint-multi-select__chip\">\n {{ chip.label }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n tabindex=\"-1\"\n class=\"mint-multi-select__chip-remove\"\n :aria-label=\"`Remove ${chip.label}`\"\n @click.stop=\"remove(chip.value)\"\n >\n <X :size=\"11\" :stroke-width=\"2.25\" aria-hidden=\"true\" />\n </button>\n </span>\n <span v-if=\"chips.length === 0\" class=\"mint-multi-select__placeholder\">{{ placeholder }}</span>\n </div>\n <ChevronDown class=\"mint-multi-select__icon\" :size=\"14\" aria-hidden=\"true\" />\n </div>\n\n <div v-if=\"open\" ref=\"panel\" class=\"mint-popover mint-searchable-select__panel\" :style=\"panelStyle\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n placeholder=\"Filter…\"\n aria-label=\"Filter options\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\" aria-multiselectable=\"true\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-multi-select__option\"\n :class=\"{ 'mint-menu-item--active': activeIndex === index }\"\n :aria-selected=\"selection.isSelected(option.value)\"\n :aria-disabled=\"isUnavailable(option) || undefined\"\n @mousedown.prevent\n @mouseenter=\"!isUnavailable(option) && (activeIndex = index)\"\n @click=\"toggle(option)\"\n >\n <span\n :class=\"['mint-multi-select__check', { 'mint-multi-select__check--on': selection.isSelected(option.value) }]\"\n aria-hidden=\"true\"\n >\n <Check v-if=\"selection.isSelected(option.value)\" :size=\"10\" :stroke-width=\"3.5\" />\n </span>\n <span class=\"mint-menu-item__label\">{{ option.label }}</span>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">No matching options</li>\n </ul>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `multiple`: a field of removable chips that opens a filterable checkbox listbox, capped by `max`. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport { Check, ChevronDown, X } from 'lucide-vue-next'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { useFloatingPanel } from '../../composables/useFloatingPanel'\nimport { useListSelection } from '../../composables/useListSelection'\nimport { normalizeOptionInput } from '../../utils/options'\n\ntype MultiOption = SelectOption<OptionPrimitive>\n\ninterface Props {\n modelValue: OptionPrimitive[]\n options: SelectOptionInput[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n max?: number\n size?: 'sm' | 'md' | 'lg'\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select options...',\n disabled: false,\n invalid: false,\n max: undefined,\n size: 'md',\n ariaLabelledby: undefined,\n ariaDescribedby: undefined,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focusable field.\nconst attrs = useAttrs()\nconst fieldAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: OptionPrimitive[]]\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-multi-select-${id}`\nconst root = ref<HTMLElement | null>(null)\nconst field = ref<HTMLElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst panel = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\n\nconst normalizedOptions = computed<MultiOption[]>(() => props.options.map(normalizeOptionInput<OptionPrimitive, MultiOption>))\nconst selection = useListSelection({\n selected: () => props.modelValue,\n items: normalizedOptions,\n getValue: option => option.value,\n disabled: () => props.disabled,\n max: () => props.max,\n})\n\nconst chips = computed(() => props.modelValue.map(value => ({\n value,\n label: normalizedOptions.value.find(option => option.value === value)?.label ?? String(value),\n})))\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option => option.label.toLocaleLowerCase().includes(needle))\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction isUnavailable(option: MultiOption): boolean {\n return !!option.disabled || (!selection.isSelected(option.value) && !selection.canAddMore.value)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled || open.value) return\n query.value = ''\n open.value = true\n activeIndex.value = visibleOptions.value.length > 0 ? 0 : -1\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n field.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const count = visibleOptions.value.length\n if (count === 0) return\n const start = activeIndex.value < 0 ? (direction === 1 ? -1 : count) : activeIndex.value\n activeIndex.value = (start + direction + count) % count\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction toggle(option: MultiOption): void {\n if (props.disabled || isUnavailable(option)) return\n emit('update:modelValue', selection.toggleValue(option.value))\n}\n\nfunction remove(value: OptionPrimitive): void {\n if (props.disabled) return\n emit('update:modelValue', props.modelValue.filter(selected => selected !== value))\n}\n\nfunction handleFieldKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Enter' && event.key !== ' ' && event.key !== 'ArrowDown') return\n event.preventDefault()\n void openPanel()\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) toggle(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else if (event.key === 'Backspace' && query.value === '' && props.modelValue.length > 0) {\n remove(props.modelValue[props.modelValue.length - 1]!)\n } else return\n event.preventDefault()\n}\n\n// Fixed next to the field, so a modal body's overflow does not clip it; it stays in place in the DOM.\nconst { style: panelStyle } = useFloatingPanel(field, panel, open, { matchWidth: true })\n\nwatch(visibleOptions, options => { activeIndex.value = options.length > 0 ? 0 : -1 })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-multi-select', `mint-multi-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <div\n v-bind=\"fieldAttrs\"\n ref=\"field\"\n role=\"combobox\"\n :tabindex=\"disabled ? undefined : 0\"\n :class=\"[\n 'mint-multi-select__field',\n {\n 'mint-multi-select__field--open': open,\n 'mint-multi-select__field--error': invalid,\n 'mint-multi-select__field--disabled': disabled,\n },\n ]\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-disabled=\"disabled || undefined\"\n :aria-invalid=\"invalid || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown.self=\"handleFieldKeydown\"\n >\n <div class=\"mint-multi-select__chips\">\n <span v-for=\"chip in chips\" :key=\"String(chip.value)\" class=\"mint-multi-select__chip\">\n {{ chip.label }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n tabindex=\"-1\"\n class=\"mint-multi-select__chip-remove\"\n :aria-label=\"`Remove ${chip.label}`\"\n @click.stop=\"remove(chip.value)\"\n >\n <X :size=\"11\" :stroke-width=\"2.25\" aria-hidden=\"true\" />\n </button>\n </span>\n <span v-if=\"chips.length === 0\" class=\"mint-multi-select__placeholder\">{{ placeholder }}</span>\n </div>\n <ChevronDown class=\"mint-multi-select__icon\" :size=\"14\" aria-hidden=\"true\" />\n </div>\n\n <div v-if=\"open\" ref=\"panel\" class=\"mint-popover mint-searchable-select__panel\" :style=\"panelStyle\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n placeholder=\"Filter…\"\n aria-label=\"Filter options\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\" aria-multiselectable=\"true\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-multi-select__option\"\n :class=\"{ 'mint-menu-item--active': activeIndex === index }\"\n :aria-selected=\"selection.isSelected(option.value)\"\n :aria-disabled=\"isUnavailable(option) || undefined\"\n @mousedown.prevent\n @mouseenter=\"!isUnavailable(option) && (activeIndex = index)\"\n @click=\"toggle(option)\"\n >\n <span\n :class=\"['mint-multi-select__check', { 'mint-multi-select__check--on': selection.isSelected(option.value) }]\"\n aria-hidden=\"true\"\n >\n <Check v-if=\"selection.isSelected(option.value)\" :size=\"10\" :stroke-width=\"3.5\" />\n </span>\n <span class=\"mint-menu-item__label\">{{ option.label }}</span>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">No matching options</li>\n </ul>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `searchable`: a single-select listbox with a search field, descriptions, disabled reasons, and custom slots. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport { ChevronsUpDown } from 'lucide-vue-next'\nimport type { SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { useFloatingPanel } from '../../composables/useFloatingPanel'\nimport { normalizeOptionInput } from '../../utils/options'\n\ninterface Props {\n modelValue?: string | number | null\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n searchPlaceholder?: string\n noResultsText?: string\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n invalid?: boolean\n /** Id of the visible label; the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select an option',\n searchPlaceholder: 'Search options…',\n noResultsText: 'No matching options',\n size: 'md',\n disabled: false,\n invalid: false,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focused trigger.\nconst attrs = useAttrs()\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\ndefineSlots<{\n option?: (props: { option: SelectOption<string | number>; selected: boolean; active: boolean }) => unknown\n footer?: () => unknown\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-searchable-select-${id}`\nconst triggerId = `${listboxId}-trigger`\nconst root = ref<HTMLElement | null>(null)\nconst trigger = ref<HTMLButtonElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst panel = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput),\n)\nconst selectedOption = computed(() =>\n normalizedOptions.value.find(option => option.value === props.modelValue),\n)\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option =>\n [option.label, option.description, option.meta, option.disabledReason]\n .some(value => value?.toLocaleLowerCase().includes(needle)),\n )\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction firstEnabledIndex(options = visibleOptions.value): number {\n return options.findIndex(option => !option.disabled)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled) return\n query.value = ''\n open.value = true\n activeIndex.value = firstEnabledIndex(normalizedOptions.value)\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n trigger.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const enabled = visibleOptions.value\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled)\n if (enabled.length === 0) return\n const current = enabled.findIndex(({ index }) => index === activeIndex.value)\n const next = current < 0\n ? (direction === 1 ? 0 : enabled.length - 1)\n : (current + direction + enabled.length) % enabled.length\n activeIndex.value = enabled[next]!.index\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction select(option: SelectOption<string | number>): void {\n if (option.disabled) return\n emit('update:modelValue', option.value)\n void closePanel(true)\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Home') activeIndex.value = firstEnabledIndex()\n else if (event.key === 'End') {\n for (let index = visibleOptions.value.length - 1; index >= 0; index--) {\n if (!visibleOptions.value[index]?.disabled) {\n activeIndex.value = index\n break\n }\n }\n } else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) select(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else return\n event.preventDefault()\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n event.preventDefault()\n void openPanel().then(() => {\n if (event.key === 'ArrowUp') moveActive(-1)\n })\n}\n\n// Fixed next to the trigger, so a modal body's overflow does not clip it; it stays in place in the DOM.\nconst { style: panelStyle } = useFloatingPanel(trigger, panel, open, { matchWidth: true })\n\nwatch(visibleOptions, options => { activeIndex.value = firstEnabledIndex(options) })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-searchable-select', `mint-searchable-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <button\n v-bind=\"triggerAttrs\"\n :id=\"triggerId\"\n ref=\"trigger\"\n type=\"button\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby ? `${ariaLabelledby} ${triggerId}` : undefined\"\n :class=\"['mint-searchable-select__trigger', { 'mint-searchable-select__trigger--error': invalid }]\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n aria-haspopup=\"listbox\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown=\"handleTriggerKeydown\"\n >\n <span :class=\"['mint-searchable-select__value', { 'mint-searchable-select__value--placeholder': !selectedOption }]\">\n {{ selectedOption?.label ?? placeholder }}\n </span>\n <ChevronsUpDown :size=\"14\" aria-hidden=\"true\" />\n </button>\n\n <div v-if=\"open\" ref=\"panel\" class=\"mint-popover mint-searchable-select__panel\" :style=\"panelStyle\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n :placeholder=\"searchPlaceholder\"\n :aria-label=\"searchPlaceholder\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-searchable-select__option\"\n :class=\"{\n 'mint-menu-item--active mint-searchable-select__option--active': activeIndex === index,\n 'mint-menu-item--selected mint-searchable-select__option--selected': modelValue === option.value,\n 'mint-searchable-select__option--disabled': option.disabled,\n }\"\n :aria-selected=\"modelValue === option.value\"\n :aria-disabled=\"option.disabled || undefined\"\n @mousedown.prevent\n @mouseenter=\"!option.disabled && (activeIndex = index)\"\n @click=\"select(option)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"modelValue === option.value\" :active=\"activeIndex === index\">\n <span class=\"mint-menu-item__text mint-searchable-select__option-text\">\n <span class=\"mint-menu-item__label mint-searchable-select__option-label\">{{ option.label }}</span>\n <span v-if=\"option.disabled ? option.disabledReason || option.description : option.description\" class=\"mint-menu-item__description mint-searchable-select__option-description\">\n {{ option.disabled ? option.disabledReason || option.description : option.description }}\n </span>\n </span>\n <span v-if=\"option.meta\" class=\"mint-menu-item__meta mint-searchable-select__option-meta\">{{ option.meta }}</span>\n <svg class=\"mint-menu-item__check mint-searchable-select__check\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 10 3 3 7-7\" />\n </svg>\n </slot>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">{{ noResultsText }}</li>\n </ul>\n\n <div v-if=\"$slots.footer\" class=\"mint-searchable-select__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseSelect with `searchable`: a single-select listbox with a search field, descriptions, disabled reasons, and custom slots. */\nimport { computed, nextTick, ref, useAttrs, useId, watch } from 'vue'\nimport { ChevronsUpDown } from 'lucide-vue-next'\nimport type { SelectOption, SelectOptionInput } from '../../types'\nimport { useEventListener } from '../../composables/useEventListener'\nimport { useFloatingPanel } from '../../composables/useFloatingPanel'\nimport { normalizeOptionInput } from '../../utils/options'\n\ninterface Props {\n modelValue?: string | number | null\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n searchPlaceholder?: string\n noResultsText?: string\n size?: 'sm' | 'md' | 'lg'\n disabled?: boolean\n invalid?: boolean\n /** Id of the visible label; the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n placeholder: 'Select an option',\n searchPlaceholder: 'Search options…',\n noResultsText: 'No matching options',\n size: 'md',\n disabled: false,\n invalid: false,\n})\n\ndefineOptions({ inheritAttrs: false })\n\n// The wrapper takes class and style; every other attribute (aria-label, data-*) names the focused trigger.\nconst attrs = useAttrs()\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\ndefineSlots<{\n option?: (props: { option: SelectOption<string | number>; selected: boolean; active: boolean }) => unknown\n footer?: () => unknown\n}>()\n\nconst id = useId().replace(/:/g, '')\nconst listboxId = `mint-searchable-select-${id}`\nconst triggerId = `${listboxId}-trigger`\nconst root = ref<HTMLElement | null>(null)\nconst trigger = ref<HTMLButtonElement | null>(null)\nconst search = ref<HTMLInputElement | null>(null)\nconst panel = ref<HTMLElement | null>(null)\nconst open = ref(false)\nconst query = ref('')\nconst activeIndex = ref(-1)\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput),\n)\nconst selectedOption = computed(() =>\n normalizedOptions.value.find(option => option.value === props.modelValue),\n)\nconst visibleOptions = computed(() => {\n const needle = query.value.trim().toLocaleLowerCase()\n if (!needle) return normalizedOptions.value\n return normalizedOptions.value.filter(option =>\n [option.label, option.description, option.meta, option.disabledReason]\n .some(value => value?.toLocaleLowerCase().includes(needle)),\n )\n})\nconst activeDescendant = computed(() =>\n activeIndex.value >= 0 ? `${listboxId}-option-${activeIndex.value}` : undefined,\n)\n\nfunction firstEnabledIndex(options = visibleOptions.value): number {\n return options.findIndex(option => !option.disabled)\n}\n\nasync function openPanel(): Promise<void> {\n if (props.disabled) return\n query.value = ''\n open.value = true\n activeIndex.value = firstEnabledIndex(normalizedOptions.value)\n await nextTick()\n search.value?.focus()\n}\n\nasync function closePanel(restoreFocus = false): Promise<void> {\n open.value = false\n query.value = ''\n activeIndex.value = -1\n if (restoreFocus) {\n await nextTick()\n trigger.value?.focus()\n }\n}\n\nfunction moveActive(direction: 1 | -1): void {\n const enabled = visibleOptions.value\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled)\n if (enabled.length === 0) return\n const current = enabled.findIndex(({ index }) => index === activeIndex.value)\n const next = current < 0\n ? (direction === 1 ? 0 : enabled.length - 1)\n : (current + direction + enabled.length) % enabled.length\n activeIndex.value = enabled[next]!.index\n void nextTick(() => document.getElementById(activeDescendant.value ?? '')?.scrollIntoView({ block: 'nearest' }))\n}\n\nfunction select(option: SelectOption<string | number>): void {\n if (option.disabled) return\n emit('update:modelValue', option.value)\n void closePanel(true)\n}\n\nfunction handleSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') moveActive(1)\n else if (event.key === 'ArrowUp') moveActive(-1)\n else if (event.key === 'Home') activeIndex.value = firstEnabledIndex()\n else if (event.key === 'End') {\n for (let index = visibleOptions.value.length - 1; index >= 0; index--) {\n if (!visibleOptions.value[index]?.disabled) {\n activeIndex.value = index\n break\n }\n }\n } else if (event.key === 'Enter') {\n const option = visibleOptions.value[activeIndex.value]\n if (option) select(option)\n } else if (event.key === 'Escape') {\n void closePanel(true)\n } else return\n event.preventDefault()\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n event.preventDefault()\n void openPanel().then(() => {\n if (event.key === 'ArrowUp') moveActive(-1)\n })\n}\n\n// Fixed next to the trigger, so a modal body's overflow does not clip it; it stays in place in the DOM.\nconst { style: panelStyle } = useFloatingPanel(trigger, panel, open, { matchWidth: true })\n\nwatch(visibleOptions, options => { activeIndex.value = firstEnabledIndex(options) })\nwatch(() => props.disabled, disabled => { if (disabled) void closePanel() })\nuseEventListener(() => document, 'pointerdown', event => {\n if (open.value && !root.value?.contains(event.target as Node)) void closePanel()\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"['mint-searchable-select', `mint-searchable-select--${size}`, $attrs.class]\"\n :style=\"$attrs.style\"\n @focusout=\"!root?.contains($event.relatedTarget as Node | null) && closePanel()\"\n >\n <button\n v-bind=\"triggerAttrs\"\n :id=\"triggerId\"\n ref=\"trigger\"\n type=\"button\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby ? `${ariaLabelledby} ${triggerId}` : undefined\"\n :class=\"['mint-searchable-select__trigger', { 'mint-searchable-select__trigger--error': invalid }]\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n aria-haspopup=\"listbox\"\n @click=\"open ? closePanel() : openPanel()\"\n @keydown=\"handleTriggerKeydown\"\n >\n <span :class=\"['mint-searchable-select__value', { 'mint-searchable-select__value--placeholder': !selectedOption }]\">\n {{ selectedOption?.label ?? placeholder }}\n </span>\n <ChevronsUpDown :size=\"14\" aria-hidden=\"true\" />\n </button>\n\n <div v-if=\"open\" ref=\"panel\" class=\"mint-popover mint-searchable-select__panel\" :style=\"panelStyle\">\n <div class=\"mint-searchable-select__search-wrap\">\n <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"8.5\" cy=\"8.5\" r=\"5.5\" /><path d=\"m13 13 4 4\" />\n </svg>\n <input\n ref=\"search\"\n v-model=\"query\"\n role=\"combobox\"\n type=\"search\"\n class=\"mint-searchable-select__search\"\n :placeholder=\"searchPlaceholder\"\n :aria-label=\"searchPlaceholder\"\n :aria-expanded=\"open\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendant\"\n aria-autocomplete=\"list\"\n @keydown=\"handleSearchKeydown\"\n >\n </div>\n\n <ul :id=\"listboxId\" class=\"mint-searchable-select__list\" role=\"listbox\">\n <li\n v-for=\"(option, index) in visibleOptions\"\n :id=\"`${listboxId}-option-${index}`\"\n :key=\"String(option.value)\"\n role=\"option\"\n class=\"mint-menu-item mint-searchable-select__option\"\n :class=\"{\n 'mint-menu-item--active mint-searchable-select__option--active': activeIndex === index,\n 'mint-menu-item--selected mint-searchable-select__option--selected': modelValue === option.value,\n 'mint-searchable-select__option--disabled': option.disabled,\n }\"\n :aria-selected=\"modelValue === option.value\"\n :aria-disabled=\"option.disabled || undefined\"\n @mousedown.prevent\n @mouseenter=\"!option.disabled && (activeIndex = index)\"\n @click=\"select(option)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"modelValue === option.value\" :active=\"activeIndex === index\">\n <span class=\"mint-menu-item__text mint-searchable-select__option-text\">\n <span class=\"mint-menu-item__label mint-searchable-select__option-label\">{{ option.label }}</span>\n <span v-if=\"option.disabled ? option.disabledReason || option.description : option.description\" class=\"mint-menu-item__description mint-searchable-select__option-description\">\n {{ option.disabled ? option.disabledReason || option.description : option.description }}\n </span>\n </span>\n <span v-if=\"option.meta\" class=\"mint-menu-item__meta mint-searchable-select__option-meta\">{{ option.meta }}</span>\n <svg class=\"mint-menu-item__check mint-searchable-select__check\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" aria-hidden=\"true\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 10 3 3 7-7\" />\n </svg>\n </slot>\n </li>\n <li v-if=\"visibleOptions.length === 0\" class=\"mint-searchable-select__empty\">{{ noResultsText }}</li>\n </ul>\n\n <div v-if=\"$slots.footer\" class=\"mint-searchable-select__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"M extends boolean = false\">\n/**\n * Select one or several options.\n * Default: a native `<select>`. `searchable`: a listbox with a search field and the `#option` / `#footer` slots.\n * `multiple`: a field of removable chips with a filterable checkbox listbox, bound to an array and capped by `max`.\n *\n * @example\n * ```vue\n * <BaseSelect v-model=\"method\" :options=\"methods\" />\n * <BaseSelect v-model=\"template\" :options=\"templates\" searchable placeholder=\"Select template…\" />\n * <BaseSelect v-model=\"instrumentIds\" :options=\"instruments\" multiple :max=\"3\" />\n * ```\n */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\nimport SelectMultipleInternal from './internal/SelectMultipleInternal.vue'\nimport SelectSearchableInternal from './internal/SelectSearchableInternal.vue'\n\ndefineOptions({ inheritAttrs: false })\n\n\nconst props = withDefaults(defineProps<{\n /** The selected value; an array with `multiple`. */\n modelValue?: (M extends true ? OptionPrimitive[] : OptionPrimitive) | null\n options: SelectOptionInput[]\n /** Bind an array and pick several options (chip field + checkbox listbox). */\n multiple?: M\n /** Single selection in a listbox with a search field. Ignored with `multiple`. */\n searchable?: boolean\n /** Most options a `multiple` select accepts. */\n max?: number\n placeholder?: string\n /** Search field placeholder (`searchable`). */\n searchPlaceholder?: string\n /** Text shown when the search matches no option (`searchable`). */\n noResultsText?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n /** Id of the visible label. `searchable`: the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n}>(), {\n modelValue: null,\n multiple: undefined,\n searchable: false,\n max: undefined,\n placeholder: undefined,\n searchPlaceholder: undefined,\n noResultsText: undefined,\n disabled: false,\n invalid: false,\n size: 'md',\n ariaDescribedby: undefined,\n ariaLabelledby: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: M extends true ? OptionPrimitive[] : OptionPrimitive]\n}>()\n\ndefineSlots<{\n /** `searchable` only: custom option row. */\n option?: (props: { option: SelectOption<OptionPrimitive>; selected: boolean; active: boolean }) => unknown\n /** `searchable` only: content under the option list. */\n footer?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst normalizedOptions = computed<SelectOption<OptionPrimitive>[]>(() =>\n props.options.map(option => normalizeOptionInput<OptionPrimitive, SelectOption<OptionPrimitive>>(option)),\n)\n\n// `multiple` has the generic type `M`, so Vue declares no runtime Boolean type for it and\n// does not cast the bare attribute: `<BaseSelect multiple>` arrives as ''.\nconst isMultiple = computed(() => props.multiple === true || (props.multiple as unknown) === '')\n\nconst multipleValue = computed<OptionPrimitive[]>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? value : []\n})\nconst singleValue = computed<OptionPrimitive | null>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? null : (value as OptionPrimitive | null)\n})\n\nfunction update(value: OptionPrimitive | OptionPrimitive[]) {\n emit('update:modelValue', value as M extends true ? OptionPrimitive[] : OptionPrimitive)\n}\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n update(option?.value ?? target.value)\n}\n</script>\n\n<template>\n <SelectMultipleInternal\n v-if=\"isMultiple\"\n v-bind=\"attrs\"\n :model-value=\"multipleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :max=\"max\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n />\n <SelectSearchableInternal\n v-else-if=\"searchable\"\n v-bind=\"attrs\"\n :model-value=\"singleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :search-placeholder=\"searchPlaceholder\"\n :no-results-text=\"noResultsText\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n >\n <template v-if=\"$slots.option\" #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n </SelectSearchableInternal>\n <div v-else v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"singleValue ?? ''\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n invalid ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"M extends boolean = false\">\n/**\n * Select one or several options.\n * Default: a native `<select>`. `searchable`: a listbox with a search field and the `#option` / `#footer` slots.\n * `multiple`: a field of removable chips with a filterable checkbox listbox, bound to an array and capped by `max`.\n *\n * @example\n * ```vue\n * <BaseSelect v-model=\"method\" :options=\"methods\" />\n * <BaseSelect v-model=\"template\" :options=\"templates\" searchable placeholder=\"Select template…\" />\n * <BaseSelect v-model=\"instrumentIds\" :options=\"instruments\" multiple :max=\"3\" />\n * ```\n */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { OptionPrimitive, SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\nimport SelectMultipleInternal from './internal/SelectMultipleInternal.vue'\nimport SelectSearchableInternal from './internal/SelectSearchableInternal.vue'\n\ndefineOptions({ inheritAttrs: false })\n\n\nconst props = withDefaults(defineProps<{\n /** The selected value; an array with `multiple`. */\n modelValue?: (M extends true ? OptionPrimitive[] : OptionPrimitive) | null\n options: SelectOptionInput[]\n /** Bind an array and pick several options (chip field + checkbox listbox). */\n multiple?: M\n /** Single selection in a listbox with a search field. Ignored with `multiple`. */\n searchable?: boolean\n /** Most options a `multiple` select accepts. */\n max?: number\n placeholder?: string\n /** Search field placeholder (`searchable`). */\n searchPlaceholder?: string\n /** Text shown when the search matches no option (`searchable`). */\n noResultsText?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n /** Id of the visible label. `searchable`: the trigger is then named by the label and the selected value. */\n ariaLabelledby?: string\n}>(), {\n modelValue: null,\n multiple: undefined,\n searchable: false,\n max: undefined,\n placeholder: undefined,\n searchPlaceholder: undefined,\n noResultsText: undefined,\n disabled: false,\n invalid: false,\n size: 'md',\n ariaDescribedby: undefined,\n ariaLabelledby: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: M extends true ? OptionPrimitive[] : OptionPrimitive]\n}>()\n\ndefineSlots<{\n /** `searchable` only: custom option row. */\n option?: (props: { option: SelectOption<OptionPrimitive>; selected: boolean; active: boolean }) => unknown\n /** `searchable` only: content under the option list. */\n footer?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst normalizedOptions = computed<SelectOption<OptionPrimitive>[]>(() =>\n props.options.map(option => normalizeOptionInput<OptionPrimitive, SelectOption<OptionPrimitive>>(option)),\n)\n\n// `multiple` has the generic type `M`, so Vue declares no runtime Boolean type for it and\n// does not cast the bare attribute: `<BaseSelect multiple>` arrives as ''.\nconst isMultiple = computed(() => props.multiple === true || (props.multiple as unknown) === '')\n\nconst multipleValue = computed<OptionPrimitive[]>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? value : []\n})\nconst singleValue = computed<OptionPrimitive | null>(() => {\n const value: unknown = props.modelValue\n return Array.isArray(value) ? null : (value as OptionPrimitive | null)\n})\n\nfunction update(value: OptionPrimitive | OptionPrimitive[]) {\n emit('update:modelValue', value as M extends true ? OptionPrimitive[] : OptionPrimitive)\n}\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n update(option?.value ?? target.value)\n}\n</script>\n\n<template>\n <SelectMultipleInternal\n v-if=\"isMultiple\"\n v-bind=\"attrs\"\n :model-value=\"multipleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :max=\"max\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n />\n <SelectSearchableInternal\n v-else-if=\"searchable\"\n v-bind=\"attrs\"\n :model-value=\"singleValue\"\n :options=\"options\"\n :placeholder=\"placeholder\"\n :search-placeholder=\"searchPlaceholder\"\n :no-results-text=\"noResultsText\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-describedby=\"ariaDescribedby\"\n @update:model-value=\"update\"\n >\n <template v-if=\"$slots.option\" #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n </SelectSearchableInternal>\n <div v-else v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"singleValue ?? ''\"\n :disabled=\"disabled\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :aria-labelledby=\"ariaLabelledby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n invalid ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Floating tooltip using @floating-ui with auto-flip, delay, optional keyboard shortcut badge, and body Teleport. */\nimport { ref, onBeforeUnmount } from 'vue'\nimport { useFloatingPanel } from '../composables/useFloatingPanel'\n\ninterface Props {\n text: string\n position?: 'top' | 'bottom' | 'left' | 'right'\n delay?: number\n shortcut?: string\n maxWidth?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n position: 'top',\n delay: 200,\n shortcut: undefined,\n maxWidth: undefined,\n})\n\nconst tooltipId = `mint-tooltip-${Math.random().toString(36).slice(2, 9)}`\nconst visible = ref(false)\nconst triggerRef = ref<HTMLElement | null>(null)\nconst contentRef = ref<HTMLElement | null>(null)\nlet timeoutId: ReturnType<typeof setTimeout> | undefined\n\n// Follows the trigger while visible; the placement after flip picks the arrow side.\nconst { style: coords, placement: actualPlacement } = useFloatingPanel(triggerRef, contentRef, visible, {\n placement: () => props.position,\n offset: 6,\n})\n\nfunction show() {\n timeoutId = setTimeout(() => {\n visible.value = true\n }, props.delay)\n}\n\nfunction hide() {\n clearTimeout(timeoutId)\n timeoutId = undefined\n visible.value = false\n}\n\nonBeforeUnmount(() => {\n clearTimeout(timeoutId)\n})\n\nfunction resolvedMaxWidth(value: string | number | undefined): string | undefined {\n if (value === undefined) return undefined\n return typeof value === 'number' ? `${value}px` : value\n}\n</script>\n\n<template>\n <span\n ref=\"triggerRef\"\n class=\"mint-tooltip\"\n :aria-describedby=\"visible ? tooltipId : undefined\"\n @mouseenter=\"show\"\n @mouseleave=\"hide\"\n @focusin=\"show\"\n @focusout=\"hide\"\n >\n <slot />\n <Teleport to=\"body\">\n <span\n v-if=\"visible\"\n :id=\"tooltipId\"\n ref=\"contentRef\"\n :class=\"[\n 'mint-tooltip__content',\n `mint-tooltip__content--${actualPlacement}`,\n maxWidth ? 'mint-tooltip__content--multiline' : '',\n ]\"\n :style=\"{\n ...coords,\n maxWidth: resolvedMaxWidth(maxWidth),\n }\"\n role=\"tooltip\"\n >\n <span class=\"mint-tooltip__body\">{{ text }}</span>\n <kbd v-if=\"shortcut\" class=\"mint-tooltip__shortcut\">{{ shortcut }}</kbd>\n </span>\n </Teleport>\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** Floating tooltip using @floating-ui with auto-flip, delay, optional keyboard shortcut badge, and body Teleport. */\nimport { ref, onBeforeUnmount } from 'vue'\nimport { useFloatingPanel } from '../composables/useFloatingPanel'\n\ninterface Props {\n text: string\n position?: 'top' | 'bottom' | 'left' | 'right'\n delay?: number\n shortcut?: string\n maxWidth?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n position: 'top',\n delay: 200,\n shortcut: undefined,\n maxWidth: undefined,\n})\n\nconst tooltipId = `mint-tooltip-${Math.random().toString(36).slice(2, 9)}`\nconst visible = ref(false)\nconst triggerRef = ref<HTMLElement | null>(null)\nconst contentRef = ref<HTMLElement | null>(null)\nlet timeoutId: ReturnType<typeof setTimeout> | undefined\n\n// Follows the trigger while visible; the placement after flip picks the arrow side.\nconst { style: coords, placement: actualPlacement } = useFloatingPanel(triggerRef, contentRef, visible, {\n placement: () => props.position,\n offset: 6,\n})\n\nfunction show() {\n timeoutId = setTimeout(() => {\n visible.value = true\n }, props.delay)\n}\n\nfunction hide() {\n clearTimeout(timeoutId)\n timeoutId = undefined\n visible.value = false\n}\n\nonBeforeUnmount(() => {\n clearTimeout(timeoutId)\n})\n\nfunction resolvedMaxWidth(value: string | number | undefined): string | undefined {\n if (value === undefined) return undefined\n return typeof value === 'number' ? `${value}px` : value\n}\n</script>\n\n<template>\n <span\n ref=\"triggerRef\"\n class=\"mint-tooltip\"\n :aria-describedby=\"visible ? tooltipId : undefined\"\n @mouseenter=\"show\"\n @mouseleave=\"hide\"\n @focusin=\"show\"\n @focusout=\"hide\"\n >\n <slot />\n <Teleport to=\"body\">\n <span\n v-if=\"visible\"\n :id=\"tooltipId\"\n ref=\"contentRef\"\n :class=\"[\n 'mint-tooltip__content',\n `mint-tooltip__content--${actualPlacement}`,\n maxWidth ? 'mint-tooltip__content--multiline' : '',\n ]\"\n :style=\"{\n ...coords,\n maxWidth: resolvedMaxWidth(maxWidth),\n }\"\n role=\"tooltip\"\n >\n <span class=\"mint-tooltip__body\">{{ text }}</span>\n <kbd v-if=\"shortcut\" class=\"mint-tooltip__shortcut\">{{ shortcut }}</kbd>\n </span>\n </Teleport>\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** BaseCheckbox with `type=\"switch\"`: an on/off switch with label, size, and keyboard interaction support. */\nimport Tooltip from '../Tooltip.vue'\n\ninterface Props {\n modelValue?: boolean\n label?: string\n /** Accessible switch name; defaults to the visual label, then \"Toggle\". */\n ariaLabel?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n reverse?: boolean\n layout?: 'inline' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false,\n size: 'md',\n reverse: false,\n layout: 'inline',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction toggle() {\n if (!props.disabled) {\n emit('update:modelValue', !props.modelValue)\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n toggle()\n }\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-toggle',\n `mint-toggle--${layout}`,\n reverse ? 'mint-toggle--reverse' : '',\n disabled ? 'mint-toggle--disabled' : '',\n modelValue ? 'mint-toggle--checked' : '',\n ]\"\n @click=\"toggle\"\n >\n <span\n v-if=\"layout === 'row' && icon\"\n class=\"mint-toggle__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(icon)\"\n class=\"mint-toggle__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(icon)\">\n <path v-for=\"(d, i) in icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"icon\" />\n </svg>\n <span v-else class=\"mint-toggle__row-text-icon\">{{ icon }}</span>\n </span>\n <span\n v-if=\"layout === 'row' && label\"\n class=\"mint-toggle__copy\"\n >\n <Tooltip\n v-if=\"description\"\n :text=\"description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-toggle__label', `mint-toggle__label--${size}`, 'mint-toggle__label--tooltip']\">\n {{ label }}\n </span>\n </Tooltip>\n <span\n v-else\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </span>\n <div\n role=\"switch\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-checked=\"modelValue\"\n :aria-label=\"ariaLabel || label || 'Toggle'\"\n :class=\"[\n 'mint-toggle__track',\n `mint-toggle__track--${size}`,\n modelValue ? 'mint-toggle__track--on' : 'mint-toggle__track--off',\n ]\"\n @keydown=\"handleKeydown\"\n >\n <span :class=\"['mint-toggle__knob', `mint-toggle__knob--${size}`]\" />\n </div>\n <span\n v-if=\"label && layout !== 'row'\"\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** BaseCheckbox with `type=\"switch\"`: an on/off switch with label, size, and keyboard interaction support. */\nimport Tooltip from '../Tooltip.vue'\n\ninterface Props {\n modelValue?: boolean\n label?: string\n /** Accessible switch name; defaults to the visual label, then \"Toggle\". */\n ariaLabel?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n reverse?: boolean\n layout?: 'inline' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n disabled: false,\n size: 'md',\n reverse: false,\n layout: 'inline',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction toggle() {\n if (!props.disabled) {\n emit('update:modelValue', !props.modelValue)\n }\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n toggle()\n }\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mint-toggle',\n `mint-toggle--${layout}`,\n reverse ? 'mint-toggle--reverse' : '',\n disabled ? 'mint-toggle--disabled' : '',\n modelValue ? 'mint-toggle--checked' : '',\n ]\"\n @click=\"toggle\"\n >\n <span\n v-if=\"layout === 'row' && icon\"\n class=\"mint-toggle__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(icon)\"\n class=\"mint-toggle__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(icon)\">\n <path v-for=\"(d, i) in icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"icon\" />\n </svg>\n <span v-else class=\"mint-toggle__row-text-icon\">{{ icon }}</span>\n </span>\n <span\n v-if=\"layout === 'row' && label\"\n class=\"mint-toggle__copy\"\n >\n <Tooltip\n v-if=\"description\"\n :text=\"description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-toggle__label', `mint-toggle__label--${size}`, 'mint-toggle__label--tooltip']\">\n {{ label }}\n </span>\n </Tooltip>\n <span\n v-else\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </span>\n <div\n role=\"switch\"\n :tabindex=\"disabled ? -1 : 0\"\n :aria-checked=\"modelValue\"\n :aria-label=\"ariaLabel || label || 'Toggle'\"\n :class=\"[\n 'mint-toggle__track',\n `mint-toggle__track--${size}`,\n modelValue ? 'mint-toggle__track--on' : 'mint-toggle__track--off',\n ]\"\n @keydown=\"handleKeydown\"\n >\n <span :class=\"['mint-toggle__knob', `mint-toggle__knob--${size}`]\" />\n </div>\n <span\n v-if=\"label && layout !== 'row'\"\n :class=\"['mint-toggle__label', `mint-toggle__label--${size}`]\"\n >\n {{ label }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled checkbox with an optional label, size variants, and disabled state.\n * `type=\"switch\"` renders an on/off switch; `layout=\"row\"` renders a full-width settings row.\n *\n * @example\n * ```vue\n * <BaseCheckbox v-model=\"agree\" label=\"I agree\" />\n * <BaseCheckbox v-model=\"enabled\" type=\"switch\" label=\"Enable auto-update\" />\n * ```\n */\nimport Tooltip from './Tooltip.vue'\nimport CheckboxSwitchInternal from './internal/CheckboxSwitchInternal.vue'\n\ninterface Props {\n modelValue?: boolean\n /** `checkbox` (default) or an on/off `switch`. */\n type?: 'checkbox' | 'switch'\n /** Partially checked (e.g. select-all over a partial selection); sets `aria-checked=\"mixed\"`. */\n indeterminate?: boolean\n /** Accessible name for the native input when no visible `label` is rendered (e.g. table rows). */\n ariaLabel?: string\n label?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n layout?: 'inline' | 'row'\n /** Switch only: place the switch before the label. */\n reverse?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n indeterminate: false,\n disabled: false,\n type: 'checkbox',\n size: 'md',\n layout: 'inline',\n reverse: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.checked)\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <CheckboxSwitchInternal\n v-if=\"props.type === 'switch'\"\n :model-value=\"props.modelValue\"\n :label=\"props.label\"\n :aria-label=\"props.ariaLabel\"\n :description=\"props.description\"\n :icon=\"props.icon\"\n :icon-color=\"props.iconColor\"\n :icon-bg=\"props.iconBg\"\n :disabled=\"props.disabled\"\n :size=\"props.size\"\n :reverse=\"props.reverse\"\n :layout=\"props.layout\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n />\n <label\n v-else\n :class=\"[\n 'mint-checkbox',\n `mint-checkbox--${props.layout}`,\n props.disabled ? 'mint-checkbox--disabled' : '',\n props.modelValue ? 'mint-checkbox--checked' : '',\n ]\"\n >\n <span\n v-if=\"props.layout === 'row' && props.icon\"\n class=\"mint-checkbox__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(props.icon)\"\n class=\"mint-checkbox__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(props.icon)\">\n <path v-for=\"(d, i) in props.icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"props.icon\" />\n </svg>\n <span v-else class=\"mint-checkbox__row-text-icon\">{{ props.icon }}</span>\n </span>\n <span\n v-if=\"props.layout === 'row' && props.label\"\n class=\"mint-checkbox__copy\"\n >\n <Tooltip\n v-if=\"props.description\"\n :text=\"props.description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`, 'mint-checkbox__label--tooltip']\">\n {{ props.label }}\n </span>\n </Tooltip>\n <span v-else :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </span>\n <div class=\"mint-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n :checked=\"props.modelValue\"\n :indeterminate=\"props.indeterminate\"\n :aria-checked=\"props.indeterminate ? 'mixed' : undefined\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel || props.label || 'Checkbox'\"\n class=\"mint-checkbox__native\"\n @change=\"handleChange\"\n />\n <div\n :class=\"[\n 'mint-checkbox__box',\n `mint-checkbox__box--${props.size}`,\n props.modelValue && !props.indeterminate ? 'mint-checkbox__box--checked' : '',\n props.indeterminate ? 'mint-checkbox__box--indeterminate' : '',\n ]\"\n >\n <svg\n v-if=\"props.indeterminate\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 16 16\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-width=\"2.2\" d=\"M4 8h8\" />\n </svg>\n <svg\n v-else-if=\"props.modelValue\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"3\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <span v-if=\"props.label && props.layout !== 'row'\" :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </label>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled checkbox with an optional label, size variants, and disabled state.\n * `type=\"switch\"` renders an on/off switch; `layout=\"row\"` renders a full-width settings row.\n *\n * @example\n * ```vue\n * <BaseCheckbox v-model=\"agree\" label=\"I agree\" />\n * <BaseCheckbox v-model=\"enabled\" type=\"switch\" label=\"Enable auto-update\" />\n * ```\n */\nimport Tooltip from './Tooltip.vue'\nimport CheckboxSwitchInternal from './internal/CheckboxSwitchInternal.vue'\n\ninterface Props {\n modelValue?: boolean\n /** `checkbox` (default) or an on/off `switch`. */\n type?: 'checkbox' | 'switch'\n /** Partially checked (e.g. select-all over a partial selection); sets `aria-checked=\"mixed\"`. */\n indeterminate?: boolean\n /** Accessible name for the native input when no visible `label` is rendered (e.g. table rows). */\n ariaLabel?: string\n label?: string\n description?: string\n icon?: string | string[]\n iconColor?: string\n iconBg?: string\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n layout?: 'inline' | 'row'\n /** Switch only: place the switch before the label. */\n reverse?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n indeterminate: false,\n disabled: false,\n type: 'checkbox',\n size: 'md',\n layout: 'inline',\n reverse: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLInputElement\n emit('update:modelValue', target.checked)\n}\n\nfunction isSvgIcon(icon?: string | string[]): boolean {\n if (!icon) return false\n return Array.isArray(icon) || icon.startsWith('M') || icon.startsWith('m')\n}\n\nfunction iconStyle(): Record<string, string> {\n return {\n color: props.iconColor ?? (props.modelValue ? 'var(--color-primary)' : 'var(--text-muted)'),\n }\n}\n</script>\n\n<template>\n <CheckboxSwitchInternal\n v-if=\"props.type === 'switch'\"\n :model-value=\"props.modelValue\"\n :label=\"props.label\"\n :aria-label=\"props.ariaLabel\"\n :description=\"props.description\"\n :icon=\"props.icon\"\n :icon-color=\"props.iconColor\"\n :icon-bg=\"props.iconBg\"\n :disabled=\"props.disabled\"\n :size=\"props.size\"\n :reverse=\"props.reverse\"\n :layout=\"props.layout\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n />\n <label\n v-else\n :class=\"[\n 'mint-checkbox',\n `mint-checkbox--${props.layout}`,\n props.disabled ? 'mint-checkbox--disabled' : '',\n props.modelValue ? 'mint-checkbox--checked' : '',\n ]\"\n >\n <span\n v-if=\"props.layout === 'row' && props.icon\"\n class=\"mint-checkbox__row-icon\"\n :style=\"iconStyle()\"\n aria-hidden=\"true\"\n >\n <svg\n v-if=\"isSvgIcon(props.icon)\"\n class=\"mint-checkbox__row-svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(props.icon)\">\n <path v-for=\"(d, i) in props.icon\" :key=\"i\" :d=\"d\" />\n </template>\n <path v-else :d=\"props.icon\" />\n </svg>\n <span v-else class=\"mint-checkbox__row-text-icon\">{{ props.icon }}</span>\n </span>\n <span\n v-if=\"props.layout === 'row' && props.label\"\n class=\"mint-checkbox__copy\"\n >\n <Tooltip\n v-if=\"props.description\"\n :text=\"props.description\"\n position=\"right\"\n max-width=\"16rem\"\n >\n <span :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`, 'mint-checkbox__label--tooltip']\">\n {{ props.label }}\n </span>\n </Tooltip>\n <span v-else :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </span>\n <div class=\"mint-checkbox__input-wrapper\">\n <input\n type=\"checkbox\"\n :checked=\"props.modelValue\"\n :indeterminate=\"props.indeterminate\"\n :aria-checked=\"props.indeterminate ? 'mixed' : undefined\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel || props.label || 'Checkbox'\"\n class=\"mint-checkbox__native\"\n @change=\"handleChange\"\n />\n <div\n :class=\"[\n 'mint-checkbox__box',\n `mint-checkbox__box--${props.size}`,\n props.modelValue && !props.indeterminate ? 'mint-checkbox__box--checked' : '',\n props.indeterminate ? 'mint-checkbox__box--indeterminate' : '',\n ]\"\n >\n <svg\n v-if=\"props.indeterminate\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 16 16\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-width=\"2.2\" d=\"M4 8h8\" />\n </svg>\n <svg\n v-else-if=\"props.modelValue\"\n :class=\"['mint-checkbox__icon', `mint-checkbox__icon--${props.size}`]\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"3\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n </div>\n <span v-if=\"props.label && props.layout !== 'row'\" :class=\"['mint-checkbox__label', `mint-checkbox__label--${props.size}`]\">\n {{ props.label }}\n </span>\n </label>\n</template>\n","import { nextTick } from 'vue'\n\nexport interface UseRovingFocusOptions {\n /** Selectable item ids, in DOM order. Already excludes items skipped entirely (e.g. disabled tabs). */\n ids: () => string[]\n /** The id that is currently active/selected. */\n activeId: () => string | undefined\n /** Activates an id (e.g. emit `update:modelValue`). The composable focuses the matching element afterward. */\n activate: (id: string) => void\n /** Returns the focusable element for an id, queried lazily so it reflects the post-activation DOM. */\n getElement: (id: string) => HTMLElement | null | undefined\n /** Arrow-key axis: `'horizontal'` (Left/Right, default) or `'vertical'` (Up/Down). */\n orientation?: 'horizontal' | 'vertical'\n}\n\nexport interface UseRovingFocusReturn {\n /** Bind to each item's `@keydown`. */\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * WAI-ARIA roving-tabindex navigation with automatic activation (the tabs pattern):\n * Left/Right (or Up/Down when `orientation` is `'vertical'`) move to the adjacent item\n * and activate it immediately, wrapping past the ends; Home/End jump to the first/last\n * item. Only the active item should carry `tabindex=\"0\"`; give every other item\n * `tabindex=\"-1\"`. Used by BaseTabs.\n */\nexport function useRovingFocus(options: UseRovingFocusOptions): UseRovingFocusReturn {\n const orientation = options.orientation ?? 'horizontal'\n const prevKey = orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'\n const nextKey = orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'\n\n function moveTo(id: string | undefined) {\n if (id === undefined) return\n options.activate(id)\n void nextTick(() => options.getElement(id)?.focus())\n }\n\n function handleKeydown(event: KeyboardEvent) {\n const ids = options.ids()\n if (ids.length === 0) return\n const currentIndex = ids.indexOf(options.activeId() ?? '')\n\n if (event.key === 'Home') {\n event.preventDefault()\n moveTo(ids[0])\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n moveTo(ids[ids.length - 1])\n return\n }\n if (event.key === prevKey) {\n event.preventDefault()\n moveTo(ids[currentIndex <= 0 ? ids.length - 1 : currentIndex - 1])\n return\n }\n if (event.key === nextKey) {\n event.preventDefault()\n moveTo(ids[currentIndex === -1 || currentIndex >= ids.length - 1 ? 0 : currentIndex + 1])\n }\n }\n\n return { handleKeydown }\n}\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\nimport type { Tone } from '../types'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n tone?: Tone\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n tone: 'neutral',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${tone}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${tone}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" size=\"sm\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\nimport type { Tone } from '../types'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n tone?: Tone\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n tone: 'neutral',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${tone}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${tone}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" size=\"sm\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Wraps a form control with a label, optional hint text, and validation error display. */\nimport { computed } from 'vue'\n\ninterface Props {\n label?: string\n error?: string\n hint?: string\n required?: boolean\n showOptional?: boolean\n htmlFor?: string\n /** Prefix for the label (`-label`), error and hint ids. */\n fieldId?: string\n /** `row` puts the label left and the control in a fixed 7.5rem column. Use for numbers, toggles, short enums. */\n layout?: 'stacked' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layout: 'stacked',\n})\n\nconst errorId = computed(() =>\n props.error && props.fieldId ? `${props.fieldId}-error` : undefined\n)\n\nconst hintId = computed(() =>\n !props.error && props.hint && props.fieldId ? `${props.fieldId}-hint` : undefined\n)\n\nconst describedBy = computed(() => errorId.value ?? hintId.value)\n</script>\n\n<template>\n <div :class=\"['mint-form-field', layout === 'row' ? 'mint-form-field--row' : '']\">\n <div v-if=\"label\" class=\"mint-form-field__label-row\">\n <label\n :id=\"fieldId ? `${fieldId}-label` : undefined\"\n :for=\"htmlFor\"\n class=\"mint-form-field__label\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"mint-form-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <span\n v-if=\"!required && showOptional\"\n class=\"mint-form-field__optional\"\n >\n optional\n </span>\n </div>\n\n <div v-if=\"layout === 'row'\" class=\"mint-form-field__control\">\n <slot :described-by=\"describedBy\" />\n </div>\n <slot v-else :described-by=\"describedBy\" />\n\n <p v-if=\"error\" :id=\"errorId\" class=\"mint-form-field__error\" role=\"alert\">\n {{ error }}\n </p>\n <p v-else-if=\"hint\" :id=\"hintId\" class=\"mint-form-field__hint\">\n {{ hint }}\n </p>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Wraps a form control with a label, optional hint text, and validation error display. */\nimport { computed } from 'vue'\n\ninterface Props {\n label?: string\n error?: string\n hint?: string\n required?: boolean\n showOptional?: boolean\n htmlFor?: string\n /** Prefix for the label (`-label`), error and hint ids. */\n fieldId?: string\n /** `row` puts the label left and the control in a fixed 7.5rem column. Use for numbers, toggles, short enums. */\n layout?: 'stacked' | 'row'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layout: 'stacked',\n})\n\nconst errorId = computed(() =>\n props.error && props.fieldId ? `${props.fieldId}-error` : undefined\n)\n\nconst hintId = computed(() =>\n !props.error && props.hint && props.fieldId ? `${props.fieldId}-hint` : undefined\n)\n\nconst describedBy = computed(() => errorId.value ?? hintId.value)\n</script>\n\n<template>\n <div :class=\"['mint-form-field', layout === 'row' ? 'mint-form-field--row' : '']\">\n <div v-if=\"label\" class=\"mint-form-field__label-row\">\n <label\n :id=\"fieldId ? `${fieldId}-label` : undefined\"\n :for=\"htmlFor\"\n class=\"mint-form-field__label\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"mint-form-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <span\n v-if=\"!required && showOptional\"\n class=\"mint-form-field__optional\"\n >\n optional\n </span>\n </div>\n\n <div v-if=\"layout === 'row'\" class=\"mint-form-field__control\">\n <slot :described-by=\"describedBy\" />\n </div>\n <slot v-else :described-by=\"describedBy\" />\n\n <p v-if=\"error\" :id=\"errorId\" class=\"mint-form-field__error\" role=\"alert\">\n {{ error }}\n </p>\n <p v-else-if=\"hint\" :id=\"hintId\" class=\"mint-form-field__hint\">\n {{ hint }}\n </p>\n </div>\n</template>\n","import type { TimeRange } from '../types/components'\n\nexport function parseTime(time: string): { hour: number; minute: number } {\n const [h, m] = time.split(':').map(Number)\n return { hour: h, minute: m }\n}\n\nexport function formatTime(hour: number, minute: number, format: '12h' | '24h' = '24h'): string {\n if (format === '24h') {\n return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`\n }\n const period = hour >= 12 ? 'PM' : 'AM'\n const h12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour\n return `${h12}:${String(minute).padStart(2, '0')} ${period}`\n}\n\nexport function formatTimeSlot(time: string, format: '12h' | '24h' = '24h'): string {\n const { hour, minute } = parseTime(time)\n return formatTime(hour, minute, format)\n}\n\nexport function generateTimeSlots(start: string, end: string, stepMinutes: number): string[] {\n const slots: string[] = []\n const s = parseTime(start)\n const e = parseTime(end)\n const startMin = s.hour * 60 + s.minute\n const endMin = e.hour * 60 + e.minute\n\n for (let m = startMin; m <= endMin; m += stepMinutes) {\n const hour = Math.floor(m / 60)\n const minute = m % 60\n if (hour >= 24) break\n slots.push(formatTime(hour, minute))\n }\n return slots\n}\n\nexport function rangesOverlap(a: TimeRange, b: TimeRange): boolean {\n const aStart = toMinutes(a.start)\n const aEnd = toMinutes(a.end)\n const bStart = toMinutes(b.start)\n const bEnd = toMinutes(b.end)\n return aStart < bEnd && bStart < aEnd\n}\n\nexport function durationMinutes(start: string, end: string): number {\n return toMinutes(end) - toMinutes(start)\n}\n\nexport function formatDuration(minutes: number): string {\n if (minutes < 0) return '-' + formatDuration(-minutes)\n const h = Math.floor(minutes / 60)\n const m = minutes % 60\n if (h === 0) return `${m}m`\n if (m === 0) return `${h}h`\n return `${h}h ${m}m`\n}\n\nexport function isTimeInRange(time: string, start: string, end: string): boolean {\n const t = toMinutes(time)\n return t >= toMinutes(start) && t <= toMinutes(end)\n}\n\nexport function findAvailableSlots(\n dayStart: string,\n dayEnd: string,\n occupied: TimeRange[],\n minDuration: number,\n): TimeRange[] {\n const sorted = [...occupied].sort((a, b) => toMinutes(a.start) - toMinutes(b.start))\n const available: TimeRange[] = []\n let cursor = toMinutes(dayStart)\n const end = toMinutes(dayEnd)\n\n for (const slot of sorted) {\n const slotStart = toMinutes(slot.start)\n const slotEnd = toMinutes(slot.end)\n if (slotStart > cursor && slotStart - cursor >= minDuration) {\n available.push({ start: fromMinutes(cursor), end: fromMinutes(slotStart) })\n }\n cursor = Math.max(cursor, slotEnd)\n }\n\n if (end > cursor && end - cursor >= minDuration) {\n available.push({ start: fromMinutes(cursor), end: fromMinutes(end) })\n }\n\n return available\n}\n\nexport function snapToSlot(time: string, stepMinutes: number): string {\n const total = toMinutes(time)\n const snapped = Math.round(total / stepMinutes) * stepMinutes\n return fromMinutes(snapped)\n}\n\nexport function addMinutes(time: string, minutes: number): string {\n const total = toMinutes(time) + minutes\n return fromMinutes(Math.max(0, Math.min(total, 24 * 60 - 1)))\n}\n\nexport function compareTime(a: string, b: string): number {\n const ma = toMinutes(a)\n const mb = toMinutes(b)\n if (ma < mb) return -1\n if (ma > mb) return 1\n return 0\n}\n\nexport function findNearestTimeSlotIndex(time: string, slots: readonly string[]): number {\n if (slots.length === 0) return -1\n const target = toMinutes(time)\n let bestIndex = 0\n let bestDiff = Infinity\n for (let index = 0; index < slots.length; index++) {\n const diff = Math.abs(toMinutes(slots[index]) - target)\n if (diff < bestDiff) {\n bestDiff = diff\n bestIndex = index\n }\n }\n return bestIndex\n}\n\nconst relativeTimeFormat = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })\n\n/**\n * \"in 5 minutes\" / \"2 hours ago\" up to a week, then a locale date.\n * With `weeks`, times up to five weeks away read as a week count first.\n */\nexport function formatRelativeTime(value: Date | string, { weeks = false }: { weeks?: boolean } = {}): string {\n const date = value instanceof Date ? value : new Date(value)\n const diffSec = Math.round((date.getTime() - Date.now()) / 1000)\n const diffMin = Math.round(diffSec / 60)\n const diffHr = Math.round(diffMin / 60)\n const diffDay = Math.round(diffHr / 24)\n const diffWeek = Math.round(diffDay / 7)\n if (Math.abs(diffSec) < 60) return relativeTimeFormat.format(diffSec, 'second')\n if (Math.abs(diffMin) < 60) return relativeTimeFormat.format(diffMin, 'minute')\n if (Math.abs(diffHr) < 24) return relativeTimeFormat.format(diffHr, 'hour')\n if (Math.abs(diffDay) < 7) return relativeTimeFormat.format(diffDay, 'day')\n if (weeks && Math.abs(diffWeek) < 5) return relativeTimeFormat.format(diffWeek, 'week')\n return date.toLocaleDateString()\n}\n\nexport function toMinutes(time: string): number {\n const { hour, minute } = parseTime(time)\n return hour * 60 + minute\n}\n\nexport function fromMinutes(total: number): string {\n const hour = Math.floor(total / 60) % 24\n const minute = total % 60\n return formatTime(hour, minute)\n}\n","import { nextTick } from 'vue'\n\nexport interface UseMenuKeyboardOptions {\n /** Returns the currently navigable items inside the open panel, in DOM order. */\n items: () => HTMLElement[]\n /** True while the panel is open. */\n isOpen: () => boolean\n /** Opens the panel. */\n open: () => void\n /** Closes the panel. When `returnFocus` is true, focus should return to the trigger. */\n close: (returnFocus?: boolean) => void\n}\n\nexport interface UseMenuKeyboardReturn {\n /**\n * Bind to the trigger's `@keydown`. ArrowDown/Enter/Space open the panel (when\n * closed) and focus its first item; ArrowUp opens it focused on the last item.\n */\n handleTriggerKeydown: (event: KeyboardEvent) => void\n /**\n * Bind to the open panel's `@keydown`. ArrowUp/ArrowDown cycle focus with\n * wraparound, Home/End jump to the first/last item, Escape closes, returns\n * focus to the trigger and stops propagating, and Tab closes without moving focus.\n */\n handlePanelKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * Shared keyboard contract for menu- and listbox-style disclosure panels (the\n * WAI-ARIA menu button pattern). Used by ActionMenu and the platform account menu,\n * each pairing it with `useDropdownState` for the disclosure state itself.\n */\nexport function useMenuKeyboard(options: UseMenuKeyboardOptions): UseMenuKeyboardReturn {\n function focusItem(position: 'first' | 'last') {\n void nextTick(() => {\n const items = options.items()\n const target = position === 'first' ? items[0] : items[items.length - 1]\n target?.focus()\n })\n }\n\n function handleTriggerKeydown(event: KeyboardEvent) {\n if (options.isOpen()) return\n\n if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n options.open()\n focusItem('first')\n return\n }\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n options.open()\n focusItem('last')\n }\n }\n\n function handlePanelKeydown(event: KeyboardEvent) {\n const items = options.items()\n const currentIndex = items.indexOf(document.activeElement as HTMLElement)\n\n if (event.key === 'Escape') {\n event.preventDefault()\n // The menu handles this Escape; an enclosing BaseModal must not close too.\n event.stopPropagation()\n options.close(true)\n return\n }\n if (event.key === 'Tab') {\n options.close()\n return\n }\n if (event.key === 'Home') {\n event.preventDefault()\n items[0]?.focus()\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n items[items.length - 1]?.focus()\n return\n }\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n\n event.preventDefault()\n const direction = event.key === 'ArrowDown' ? 1 : -1\n const nextIndex = (Math.max(currentIndex, 0) + direction + items.length) % items.length\n items[nextIndex]?.focus()\n }\n\n return { handleTriggerKeydown, handlePanelKeydown }\n}\n","<script setup lang=\"ts\">\n/** Drag-and-drop file upload zone with type filtering, size validation, and folder mode. */\nimport { ref, computed, watch } from 'vue'\n\ninterface Props {\n accept?: string\n multiple?: boolean\n maxSize?: number\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n mode?: 'file' | 'folder' | 'file+folder'\n /** Hide the selection list when a parent presents the files itself. */\n showFiles?: boolean\n /** Restore selections owned by a parent form; omitted for internal selection state. */\n files?: File[]\n rootName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n multiple: false,\n disabled: false,\n size: 'md',\n mode: 'file',\n showFiles: true,\n})\n\nconst emit = defineEmits<{\n upload: [files: File[], rootName?: string, relativePaths?: string[]]\n remove: [files: File[]]\n error: [message: string]\n}>()\n\nconst isDragOver = ref(false)\nconst inputRef = ref<HTMLInputElement>()\nconst selectedFiles = ref<File[]>([])\nconst folderName = ref<string | null>(null)\n\nwatch(() => [props.files, props.rootName] as const, ([files, rootName]) => {\n if (files === undefined) return\n selectedFiles.value = [...files]\n folderName.value = rootName ?? extractFolderName(files)\n}, { immediate: true })\n\nconst isFolder = computed(() => props.mode === 'folder')\nconst isMixed = computed(() => props.mode === 'file+folder')\n\nconst acceptLabel = computed(() => {\n if (!props.accept) return isFolder.value ? 'a folder' : 'any file'\n return props.accept.split(',').map(a => a.trim().replace('.', '').toUpperCase()).join(', ')\n})\n\nconst maxSizeLabel = computed(() => {\n if (!props.maxSize) return null\n if (props.maxSize >= 1024 * 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024 * 1024)).toFixed(1)} GB`\n }\n if (props.maxSize >= 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024)).toFixed(1)} MB`\n }\n if (props.maxSize >= 1024) {\n return `${(props.maxSize / 1024).toFixed(1)} KB`\n }\n return `${props.maxSize} bytes`\n})\n\nfunction fileTypeLabel(filename: string): string {\n return filename.split('.').pop()?.toUpperCase() || 'FILE'\n}\n\nfunction validateFiles(files: FileList | File[]): File[] {\n const validFiles: File[] = []\n\n for (const file of Array.from(files)) {\n if (props.maxSize && file.size > props.maxSize) {\n emit('error', `File \"${file.name}\" exceeds maximum size of ${maxSizeLabel.value}`)\n continue\n }\n\n if (props.accept) {\n const acceptedTypes = props.accept.split(',').map(t => t.trim().toLowerCase())\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase()\n const fileType = file.type.toLowerCase()\n\n const isAccepted = acceptedTypes.some(type => {\n if (type.startsWith('.')) {\n return fileExt === type\n }\n if (type.endsWith('/*')) {\n return fileType.startsWith(type.replace('/*', '/'))\n }\n return fileType === type\n })\n\n if (!isAccepted) {\n emit('error', `File \"${file.name}\" is not an accepted file type`)\n continue\n }\n }\n\n validFiles.push(file)\n }\n\n return validFiles\n}\n\nfunction handleFiles(\n files: FileList | File[],\n folder?: string,\n explicitRelativePaths?: string[],\n) {\n const candidates = Array.from(files)\n const validFiles = validateFiles(files)\n if (validFiles.length === 0) return\n const relativePaths = validFiles.map((file) => {\n const candidateIndex = candidates.indexOf(file)\n return explicitRelativePaths?.[candidateIndex]\n || file.webkitRelativePath\n || (folder ? `${folder}/${file.name}` : file.name)\n })\n\n if (isFolder.value) {\n folderName.value = folder || extractFolderName(validFiles)\n selectedFiles.value = validFiles\n emit('upload', validFiles, folderName.value ?? undefined, relativePaths)\n } else if (!props.multiple) {\n selectedFiles.value = [validFiles[0]]\n emit('upload', [validFiles[0]], undefined, [relativePaths[0]])\n } else {\n selectedFiles.value = [...selectedFiles.value, ...validFiles]\n emit('upload', validFiles, undefined, relativePaths)\n }\n}\n\nfunction extractFolderName(files: File[]): string | null {\n if (files.length === 0) return null\n const firstPath = files[0].webkitRelativePath\n if (firstPath) {\n return firstPath.split('/')[0]\n }\n return null\n}\n\nasync function handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragOver.value = false\n if (props.disabled) return\n\n try {\n if (props.mode !== 'file' && event.dataTransfer?.items?.length) {\n await handleFolderDrop(event.dataTransfer.items)\n } else if (event.dataTransfer?.files) {\n handleFiles(event.dataTransfer.files)\n }\n } catch (cause) {\n emit('error', cause instanceof Error ? cause.message : 'Could not read the dropped folder.')\n }\n}\n\nasync function handleFolderDrop(items: DataTransferItemList) {\n const files: File[] = []\n const relativePaths: string[] = []\n let folderNameFromDrop: string | undefined\n\n // Capture live drag data before awaiting: the browser protects it after the drop handler.\n const dropped = Array.from(items, (item) => {\n const entry = item.webkitGetAsEntry?.()\n return { entry, file: entry ? null : item.getAsFile?.() }\n })\n for (const { entry, file: droppedFile } of dropped) {\n if (entry?.isDirectory) {\n folderNameFromDrop = entry.name\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n entry.name,\n )\n } else {\n const file = entry?.isFile\n ? await getFile(entry as FileSystemFileEntry)\n : droppedFile\n if (file) {\n files.push(file)\n relativePaths.push(file.name)\n }\n }\n }\n\n if (files.length > 0) {\n handleFiles(files, folderNameFromDrop, relativePaths)\n }\n}\n\nasync function readDirectory(\n directory: FileSystemDirectoryEntry,\n files: File[],\n relativePaths: string[],\n prefix: string,\n): Promise<void> {\n const reader = directory.createReader()\n // readEntries returns at most 100 entries per call per spec — must loop\n let batch: FileSystemEntry[]\n do {\n batch = await new Promise<FileSystemEntry[]>((resolve, reject) => {\n reader.readEntries(resolve, reject)\n })\n for (const entry of batch) {\n if (entry.isFile) {\n const file = await getFile(entry as FileSystemFileEntry)\n if (file) {\n files.push(file)\n relativePaths.push(`${prefix}/${file.name}`)\n }\n } else if (entry.isDirectory) {\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n `${prefix}/${entry.name}`,\n )\n }\n }\n } while (batch.length > 0)\n}\n\nfunction getFile(entry: FileSystemFileEntry): Promise<File | null> {\n return new Promise((resolve) => {\n entry.file(resolve, () => resolve(null))\n })\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n if (!props.disabled) {\n isDragOver.value = true\n }\n}\n\nfunction handleDragLeave() {\n isDragOver.value = false\n}\n\nfunction handleInputChange(event: Event) {\n const target = event.target as HTMLInputElement\n if (target.files) {\n handleFiles(target.files)\n }\n target.value = ''\n}\n\nfunction openFilePicker() {\n if (!props.disabled) {\n inputRef.value?.click()\n }\n}\n\nfunction removeFile(index: number) {\n const removed = selectedFiles.value[index]\n selectedFiles.value = selectedFiles.value.filter((_, i) => i !== index)\n if (isFolder.value && selectedFiles.value.length === 0) {\n folderName.value = null\n }\n if (removed) emit('remove', [removed])\n}\n\nfunction clearAll() {\n const removed = [...selectedFiles.value]\n selectedFiles.value = []\n folderName.value = null\n if (removed.length) emit('remove', removed)\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${bytes} bytes`\n}\n</script>\n\n<template>\n <div class=\"mint-file-uploader\">\n <!-- Dropzone -->\n <div\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"disabled\n ? 'File upload disabled'\n : isMixed\n ? 'Drop files or a folder, or click to choose files'\n : isFolder ? 'Click or drag a folder to upload' : 'Click or drag files to upload'\"\n :aria-disabled=\"disabled\"\n :class=\"[\n 'mint-file-uploader__dropzone',\n `mint-file-uploader__dropzone--${size}`,\n isDragOver ? 'mint-file-uploader__dropzone--dragover' : '',\n disabled ? 'mint-file-uploader__dropzone--disabled' : '',\n selectedFiles.length > 0 ? 'mint-file-uploader__dropzone--has-files' : '',\n ]\"\n @click=\"openFilePicker\"\n @keydown.enter=\"openFilePicker\"\n @keydown.space.prevent=\"openFilePicker\"\n @drop=\"handleDrop\"\n @dragover=\"handleDragOver\"\n @dragleave=\"handleDragLeave\"\n >\n <input\n ref=\"inputRef\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"isFolder || multiple\"\n :disabled=\"disabled\"\n :webkitdirectory=\"isFolder || undefined\"\n class=\"mint-file-uploader__input\"\n @change=\"handleInputChange\"\n />\n\n <div class=\"mint-file-uploader__content\">\n <svg\n v-if=\"isFolder\"\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n <svg\n v-else\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3\" /><path d=\"m16 16-4-4-4 4\" /><path d=\"M12 12v9\" />\n </svg>\n\n <p class=\"mint-file-uploader__text\">\n {{ isMixed ? 'Drop files or a folder, or click to choose files' : `Drop ${acceptLabel} or click` }}\n </p>\n </div>\n </div>\n\n <!-- Actions slot (e.g. template buttons) -->\n <div v-if=\"$slots.actions\" class=\"mint-file-uploader__actions\">\n <slot name=\"actions\" />\n </div>\n\n <!-- Folder summary display -->\n <div v-if=\"showFiles && isFolder && folderName && selectedFiles.length > 0\" class=\"mint-file-uploader__folder-summary\">\n <div class=\"mint-file-uploader__folder-info\">\n <div class=\"mint-file-uploader__folder-icon-wrapper\">\n <svg class=\"mint-file-uploader__folder-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n </div>\n <div class=\"mint-file-uploader__folder-details\">\n <span class=\"mint-file-uploader__folder-name\">{{ folderName }}</span>\n <span class=\"mint-file-uploader__folder-count\">{{ selectedFiles.length }} file{{ selectedFiles.length !== 1 ? 's' : '' }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear folder\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"clearAll\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- File list display -->\n <TransitionGroup\n v-if=\"showFiles && !isFolder && selectedFiles.length > 0\"\n tag=\"ul\"\n name=\"mint-file-uploader-item\"\n class=\"mint-file-uploader__list\"\n >\n <li\n v-for=\"(file, index) in selectedFiles\"\n :key=\"`${file.name}-${file.size}-${index}`\"\n class=\"mint-file-uploader__file\"\n >\n <div class=\"mint-file-uploader__file-info\">\n <span class=\"mint-file-uploader__file-badge\">{{ fileTypeLabel(file.name) }}</span>\n <div class=\"mint-file-uploader__file-meta\">\n <span class=\"mint-file-uploader__file-name\">{{ file.name }}</span>\n <span class=\"mint-file-uploader__file-size\">{{ formatFileSize(file.size) }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n :aria-label=\"`Remove ${file.name}`\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"removeFile(index)\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </li>\n </TransitionGroup>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Drag-and-drop file upload zone with type filtering, size validation, and folder mode. */\nimport { ref, computed, watch } from 'vue'\n\ninterface Props {\n accept?: string\n multiple?: boolean\n maxSize?: number\n disabled?: boolean\n size?: 'sm' | 'md' | 'lg'\n mode?: 'file' | 'folder' | 'file+folder'\n /** Hide the selection list when a parent presents the files itself. */\n showFiles?: boolean\n /** Restore selections owned by a parent form; omitted for internal selection state. */\n files?: File[]\n rootName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n multiple: false,\n disabled: false,\n size: 'md',\n mode: 'file',\n showFiles: true,\n})\n\nconst emit = defineEmits<{\n upload: [files: File[], rootName?: string, relativePaths?: string[]]\n remove: [files: File[]]\n error: [message: string]\n}>()\n\nconst isDragOver = ref(false)\nconst inputRef = ref<HTMLInputElement>()\nconst selectedFiles = ref<File[]>([])\nconst folderName = ref<string | null>(null)\n\nwatch(() => [props.files, props.rootName] as const, ([files, rootName]) => {\n if (files === undefined) return\n selectedFiles.value = [...files]\n folderName.value = rootName ?? extractFolderName(files)\n}, { immediate: true })\n\nconst isFolder = computed(() => props.mode === 'folder')\nconst isMixed = computed(() => props.mode === 'file+folder')\n\nconst acceptLabel = computed(() => {\n if (!props.accept) return isFolder.value ? 'a folder' : 'any file'\n return props.accept.split(',').map(a => a.trim().replace('.', '').toUpperCase()).join(', ')\n})\n\nconst maxSizeLabel = computed(() => {\n if (!props.maxSize) return null\n if (props.maxSize >= 1024 * 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024 * 1024)).toFixed(1)} GB`\n }\n if (props.maxSize >= 1024 * 1024) {\n return `${(props.maxSize / (1024 * 1024)).toFixed(1)} MB`\n }\n if (props.maxSize >= 1024) {\n return `${(props.maxSize / 1024).toFixed(1)} KB`\n }\n return `${props.maxSize} bytes`\n})\n\nfunction fileTypeLabel(filename: string): string {\n return filename.split('.').pop()?.toUpperCase() || 'FILE'\n}\n\nfunction validateFiles(files: FileList | File[]): File[] {\n const validFiles: File[] = []\n\n for (const file of Array.from(files)) {\n if (props.maxSize && file.size > props.maxSize) {\n emit('error', `File \"${file.name}\" exceeds maximum size of ${maxSizeLabel.value}`)\n continue\n }\n\n if (props.accept) {\n const acceptedTypes = props.accept.split(',').map(t => t.trim().toLowerCase())\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase()\n const fileType = file.type.toLowerCase()\n\n const isAccepted = acceptedTypes.some(type => {\n if (type.startsWith('.')) {\n return fileExt === type\n }\n if (type.endsWith('/*')) {\n return fileType.startsWith(type.replace('/*', '/'))\n }\n return fileType === type\n })\n\n if (!isAccepted) {\n emit('error', `File \"${file.name}\" is not an accepted file type`)\n continue\n }\n }\n\n validFiles.push(file)\n }\n\n return validFiles\n}\n\nfunction handleFiles(\n files: FileList | File[],\n folder?: string,\n explicitRelativePaths?: string[],\n) {\n const candidates = Array.from(files)\n const validFiles = validateFiles(files)\n if (validFiles.length === 0) return\n const relativePaths = validFiles.map((file) => {\n const candidateIndex = candidates.indexOf(file)\n return explicitRelativePaths?.[candidateIndex]\n || file.webkitRelativePath\n || (folder ? `${folder}/${file.name}` : file.name)\n })\n\n if (isFolder.value) {\n folderName.value = folder || extractFolderName(validFiles)\n selectedFiles.value = validFiles\n emit('upload', validFiles, folderName.value ?? undefined, relativePaths)\n } else if (!props.multiple) {\n selectedFiles.value = [validFiles[0]]\n emit('upload', [validFiles[0]], undefined, [relativePaths[0]])\n } else {\n selectedFiles.value = [...selectedFiles.value, ...validFiles]\n emit('upload', validFiles, undefined, relativePaths)\n }\n}\n\nfunction extractFolderName(files: File[]): string | null {\n if (files.length === 0) return null\n const firstPath = files[0].webkitRelativePath\n if (firstPath) {\n return firstPath.split('/')[0]\n }\n return null\n}\n\nasync function handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragOver.value = false\n if (props.disabled) return\n\n try {\n if (props.mode !== 'file' && event.dataTransfer?.items?.length) {\n await handleFolderDrop(event.dataTransfer.items)\n } else if (event.dataTransfer?.files) {\n handleFiles(event.dataTransfer.files)\n }\n } catch (cause) {\n emit('error', cause instanceof Error ? cause.message : 'Could not read the dropped folder.')\n }\n}\n\nasync function handleFolderDrop(items: DataTransferItemList) {\n const files: File[] = []\n const relativePaths: string[] = []\n let folderNameFromDrop: string | undefined\n\n // Capture live drag data before awaiting: the browser protects it after the drop handler.\n const dropped = Array.from(items, (item) => {\n const entry = item.webkitGetAsEntry?.()\n return { entry, file: entry ? null : item.getAsFile?.() }\n })\n for (const { entry, file: droppedFile } of dropped) {\n if (entry?.isDirectory) {\n folderNameFromDrop = entry.name\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n entry.name,\n )\n } else {\n const file = entry?.isFile\n ? await getFile(entry as FileSystemFileEntry)\n : droppedFile\n if (file) {\n files.push(file)\n relativePaths.push(file.name)\n }\n }\n }\n\n if (files.length > 0) {\n handleFiles(files, folderNameFromDrop, relativePaths)\n }\n}\n\nasync function readDirectory(\n directory: FileSystemDirectoryEntry,\n files: File[],\n relativePaths: string[],\n prefix: string,\n): Promise<void> {\n const reader = directory.createReader()\n // readEntries returns at most 100 entries per call per spec — must loop\n let batch: FileSystemEntry[]\n do {\n batch = await new Promise<FileSystemEntry[]>((resolve, reject) => {\n reader.readEntries(resolve, reject)\n })\n for (const entry of batch) {\n if (entry.isFile) {\n const file = await getFile(entry as FileSystemFileEntry)\n if (file) {\n files.push(file)\n relativePaths.push(`${prefix}/${file.name}`)\n }\n } else if (entry.isDirectory) {\n await readDirectory(\n entry as FileSystemDirectoryEntry,\n files,\n relativePaths,\n `${prefix}/${entry.name}`,\n )\n }\n }\n } while (batch.length > 0)\n}\n\nfunction getFile(entry: FileSystemFileEntry): Promise<File | null> {\n return new Promise((resolve) => {\n entry.file(resolve, () => resolve(null))\n })\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n if (!props.disabled) {\n isDragOver.value = true\n }\n}\n\nfunction handleDragLeave() {\n isDragOver.value = false\n}\n\nfunction handleInputChange(event: Event) {\n const target = event.target as HTMLInputElement\n if (target.files) {\n handleFiles(target.files)\n }\n target.value = ''\n}\n\nfunction openFilePicker() {\n if (!props.disabled) {\n inputRef.value?.click()\n }\n}\n\nfunction removeFile(index: number) {\n const removed = selectedFiles.value[index]\n selectedFiles.value = selectedFiles.value.filter((_, i) => i !== index)\n if (isFolder.value && selectedFiles.value.length === 0) {\n folderName.value = null\n }\n if (removed) emit('remove', [removed])\n}\n\nfunction clearAll() {\n const removed = [...selectedFiles.value]\n selectedFiles.value = []\n folderName.value = null\n if (removed.length) emit('remove', removed)\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${bytes} bytes`\n}\n</script>\n\n<template>\n <div class=\"mint-file-uploader\">\n <!-- Dropzone -->\n <div\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"disabled\n ? 'File upload disabled'\n : isMixed\n ? 'Drop files or a folder, or click to choose files'\n : isFolder ? 'Click or drag a folder to upload' : 'Click or drag files to upload'\"\n :aria-disabled=\"disabled\"\n :class=\"[\n 'mint-file-uploader__dropzone',\n `mint-file-uploader__dropzone--${size}`,\n isDragOver ? 'mint-file-uploader__dropzone--dragover' : '',\n disabled ? 'mint-file-uploader__dropzone--disabled' : '',\n selectedFiles.length > 0 ? 'mint-file-uploader__dropzone--has-files' : '',\n ]\"\n @click=\"openFilePicker\"\n @keydown.enter=\"openFilePicker\"\n @keydown.space.prevent=\"openFilePicker\"\n @drop=\"handleDrop\"\n @dragover=\"handleDragOver\"\n @dragleave=\"handleDragLeave\"\n >\n <input\n ref=\"inputRef\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"isFolder || multiple\"\n :disabled=\"disabled\"\n :webkitdirectory=\"isFolder || undefined\"\n class=\"mint-file-uploader__input\"\n @change=\"handleInputChange\"\n />\n\n <div class=\"mint-file-uploader__content\">\n <svg\n v-if=\"isFolder\"\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n <svg\n v-else\n class=\"mint-file-uploader__icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3\" /><path d=\"m16 16-4-4-4 4\" /><path d=\"M12 12v9\" />\n </svg>\n\n <p class=\"mint-file-uploader__text\">\n {{ isMixed ? 'Drop files or a folder, or click to choose files' : `Drop ${acceptLabel} or click` }}\n </p>\n </div>\n </div>\n\n <!-- Actions slot (e.g. template buttons) -->\n <div v-if=\"$slots.actions\" class=\"mint-file-uploader__actions\">\n <slot name=\"actions\" />\n </div>\n\n <!-- Folder summary display -->\n <div v-if=\"showFiles && isFolder && folderName && selectedFiles.length > 0\" class=\"mint-file-uploader__folder-summary\">\n <div class=\"mint-file-uploader__folder-info\">\n <div class=\"mint-file-uploader__folder-icon-wrapper\">\n <svg class=\"mint-file-uploader__folder-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n </div>\n <div class=\"mint-file-uploader__folder-details\">\n <span class=\"mint-file-uploader__folder-name\">{{ folderName }}</span>\n <span class=\"mint-file-uploader__folder-count\">{{ selectedFiles.length }} file{{ selectedFiles.length !== 1 ? 's' : '' }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear folder\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"clearAll\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- File list display -->\n <TransitionGroup\n v-if=\"showFiles && !isFolder && selectedFiles.length > 0\"\n tag=\"ul\"\n name=\"mint-file-uploader-item\"\n class=\"mint-file-uploader__list\"\n >\n <li\n v-for=\"(file, index) in selectedFiles\"\n :key=\"`${file.name}-${file.size}-${index}`\"\n class=\"mint-file-uploader__file\"\n >\n <div class=\"mint-file-uploader__file-info\">\n <span class=\"mint-file-uploader__file-badge\">{{ fileTypeLabel(file.name) }}</span>\n <div class=\"mint-file-uploader__file-meta\">\n <span class=\"mint-file-uploader__file-name\">{{ file.name }}</span>\n <span class=\"mint-file-uploader__file-size\">{{ formatFileSize(file.size) }}</span>\n </div>\n </div>\n <button\n type=\"button\"\n :aria-label=\"`Remove ${file.name}`\"\n class=\"mint-file-uploader__remove-btn\"\n @click.stop=\"removeFile(index)\"\n >\n <svg class=\"mint-file-uploader__remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </li>\n </TransitionGroup>\n </div>\n</template>\n","import type { DatePreset, SelectOption } from '../types'\n\ninterface ExperimentCodeSource {\n id?: number | null\n experiment_code?: string | null\n}\n\nexport function formatExperimentDate(dateStr: string): string {\n try {\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n } catch {\n return dateStr\n }\n}\n\nexport function datePresetToISO(preset: DatePreset): string {\n const now = new Date()\n const days = preset === 'last_7_days' ? 7 : preset === 'last_30_days' ? 30 : 90\n const d = new Date(now.getTime() - days * 86_400_000)\n return d.toISOString()\n}\n\nexport function resolveExperimentCode(experiment: ExperimentCodeSource): string | undefined {\n if (experiment.experiment_code) return experiment.experiment_code\n return undefined\n}\n\n// Mirrors vue-router's LocationQuery, whose array members are `string | null`.\n// Declaring `string[]` here made the helper reject the very type every caller\n// passes it, so keep this assignable from LocationQuery without importing\n// vue-router (the SDK does not depend on it).\ntype RouteQueryValue = string | null | undefined | readonly (string | null | undefined)[]\ntype RouteQueryLike = Record<string, RouteQueryValue>\n\n/**\n * Reads the experiment id a deep link was opened with.\n *\n * Returns an id and never a label: a display name belongs to the platform, so\n * callers must resolve it (see `useExperimentStore().selectById`) rather than\n * derive one from the query or the id itself.\n */\nexport function experimentIdFromRoute(query: RouteQueryLike): number | null {\n const raw = query.experiment_id ?? query.experimentId\n const value = Array.isArray(raw) ? raw.find(item => typeof item === 'string') : raw\n if (typeof value !== 'string' || !value) return null\n const id = Number(value)\n return Number.isInteger(id) && id > 0 ? id : null\n}\n\nexport const DATE_PRESET_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'Any time' },\n { value: 'last_7_days', label: 'Last 7 days' },\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_90_days', label: 'Last 90 days' },\n]\n\nexport const SORT_OPTIONS: SelectOption<string>[] = [\n { value: 'created_at:desc', label: 'Newest first' },\n { value: 'created_at:asc', label: 'Oldest first' },\n { value: 'updated_at:desc', label: 'Recently updated' },\n { value: 'name:asc', label: 'Name A\\u2013Z' },\n { value: 'name:desc', label: 'Name Z\\u2013A' },\n]\n","import {\n ref,\n computed,\n provide,\n toValue,\n watch,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\nimport { useExperimentStore } from '../stores/experiment'\nimport { resolveExperimentCode } from './experiment-utils'\n\nexport interface UseAppExperimentOptions {\n /**\n * Called when the shared store adopts an experiment — a modal selection or a\n * resolved deep link. The record always comes from the platform.\n */\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n /** Unsaved changes; marks the Save button with a dot. */\n dirty?: Ref<boolean> | ComputedRef<boolean>\n}\n\nexport interface AppExperimentPopoverBinding {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: ExperimentStatus\n experimentId?: number | null\n experimentProject?: string\n experimentOwner?: string\n /** ISO timestamp of the experiment's last update. */\n experimentUpdatedAt?: string\n /** An experiment is bound but its record has not arrived yet. */\n isResolving: boolean\n /** Resolution failed; the binding is kept so the user can retry or detach. */\n error?: string\n showSave: boolean\n showDetach: boolean\n saveDisabled: boolean\n saveDisabledMessage?: string\n saveLoading: boolean\n saveSuccessMessage?: string\n dirty?: boolean\n}\n\nexport interface AppExperimentSelectorModalBinding {\n open: boolean\n currentExperimentId: number | null\n}\n\nexport interface UseAppExperimentReturn {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n closeModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport interface AppExperimentState {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\n/**\n * Projects the current experiment from the shared store into an AppTopBar app\n * shell, and owns the shell-local concerns the store has no opinion on: the\n * selector modal's open state and the save flow.\n *\n * The composable never writes a selection of its own. `ExperimentSelectorModal`\n * commits to the store and this reads back, so a displayed name can only ever\n * have come from the platform.\n *\n * @example Recommended\n * ```ts\n * const appExperiment = useAppExperiment({\n * onSelect: experiment => loadExperiment(experiment.id),\n * })\n * ```\n */\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const store = useExperimentStore()\n\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const experimentName = computed(() => store.current?.name)\n const experimentCode = computed(() =>\n store.current ? resolveExperimentCode(store.current) : undefined,\n )\n const experimentStatus = computed(() => store.current?.status)\n // Set while resolving and after a failed resolve, so the shell can tell\n // \"nothing selected\" apart from \"selected but not resolved\".\n const experimentId = computed(() => store.currentId)\n const isResolving = computed(() => store.isResolving)\n const error = computed(() => store.error)\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n const dirty = computed(() => toValue(options.dirty) ?? false)\n const experimentOwner = computed(() => {\n const owner = store.current?.created_by_user\n return owner ? [owner.first_name, owner.last_name].filter(Boolean).join(' ') || owner.username : undefined\n })\n const popover = computed<AppExperimentPopoverBinding>(() => ({\n experimentName: experimentName.value,\n experimentCode: experimentCode.value,\n experimentStatus: experimentStatus.value,\n experimentId: experimentId.value,\n experimentProject: store.current?.project_name || store.current?.project || undefined,\n experimentOwner: experimentOwner.value,\n experimentUpdatedAt: store.current?.updated_at,\n isResolving: isResolving.value,\n error: error.value ?? undefined,\n showSave: showSave.value,\n showDetach: showDetach.value,\n saveDisabled: saveDisabled.value,\n saveDisabledMessage: saveDisabledMessage.value,\n saveLoading: saveLoading.value,\n saveSuccessMessage: saveSuccessMessage.value,\n dirty: dirty.value,\n }))\n const selectorModal = computed<AppExperimentSelectorModalBinding>(() => ({\n open: showModal.value,\n currentExperimentId: experimentId.value,\n }))\n\n if (options.onSelect) {\n // Keyed by id, so a refresh of the same experiment is not a new selection.\n watch(\n () => store.current?.id,\n (id) => {\n if (id !== undefined && store.current) void options.onSelect?.(store.current)\n },\n )\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n // The save changed the record on the platform; read it back so \"Updated\" is current.\n await store.refresh()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n store.clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n}\n","import type { JobState, JobStateInput, JobStatus } from './types/jobs'\n\nconst ACTIVE_JOB_STATUSES = new Set<JobStatus>([\n 'awaiting_input',\n 'queued',\n 'running',\n])\nconst TERMINAL_JOB_STATUSES = new Set<JobStatus>([\n 'completed',\n 'failed',\n 'cancelled',\n])\n\nexport interface JobCapabilityInput {\n status: string\n can_cancel?: boolean | null\n can_delete?: boolean | null\n}\n\nexport interface JobCapabilities {\n can_cancel: boolean\n can_delete: boolean\n}\n\n/** Resolve action support while retaining one-cycle legacy status inference. */\nexport function resolveJobCapabilities(job: JobCapabilityInput): JobCapabilities {\n const legacyCanCancel = job.status === 'queued' || job.status === 'running'\n const legacyCanDelete = TERMINAL_JOB_STATUSES.has(job.status as JobStatus)\n return {\n can_cancel: typeof job.can_cancel === 'boolean' ? job.can_cancel : legacyCanCancel,\n can_delete: typeof job.can_delete === 'boolean' ? job.can_delete : legacyCanDelete,\n }\n}\n\n/** Clamp invalid or out-of-range progress values for safe display. */\nexport function normalizeJobPercent(value: number): number {\n if (!Number.isFinite(value)) return 0\n return Math.min(100, Math.max(0, value))\n}\n\n/** Create a detached canonical state without changing the transport input. */\nexport function normalizeJobState(job: JobStateInput): JobState {\n const capabilities = resolveJobCapabilities(job)\n return {\n ...job,\n definition_id: job.definition_id\n ?? (typeof job.metadata.definition_id === 'string' ? job.metadata.definition_id : null),\n result_status: job.result_status\n ?? (job.status === 'completed' && job.metadata.has_result === true ? 'available' : 'none'),\n result_expires_at: job.result_expires_at ?? null,\n progress: {\n ...job.progress,\n percent: normalizeJobPercent(job.progress.percent),\n },\n warnings: [...job.warnings],\n folders: [...job.folders],\n metadata: { ...job.metadata },\n ...capabilities,\n }\n}\n\nexport function isActiveJobStatus(status: JobStatus): boolean {\n return ACTIVE_JOB_STATUSES.has(status)\n}\n\nexport function isTerminalJobStatus(status: JobStatus): boolean {\n return TERMINAL_JOB_STATUSES.has(status)\n}\n\nexport function jobStatusLabel(status: JobStatus): string {\n const labels: Record<JobStatus, string> = {\n awaiting_input: 'Waiting for input',\n queued: 'Queued',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n cancelled: 'Cancelled',\n }\n return labels[status]\n}\n","/**\n * Stable references for plugin secret settings.\n *\n * A settings response never carries a secret's value. Every secret leaf is a\n * marker instead:\n *\n * - `{ \"$secret\": \"sec_…\", \"set\": true }` — a stored secret, referenced by a\n * stable opaque id. Send the marker back unchanged to keep the stored value.\n * - `null` — nothing stored at that position.\n * - `{ \"$secret\": null, \"locked\": true }` — the effective value comes from the\n * environment and is never written back.\n *\n * On save each secret leaf accepts the reference, a plain string (a new value),\n * or `null` (clear). Payloads carry `secret_format: \"ref\"` so a `null` reads as\n * a deliberate clear rather than the deprecated \"unchanged\" placeholder.\n */\n\n/** Reserved marker key that references a stored secret. */\nexport const REF_KEY = '$secret'\n\n/** Reserved payload key declaring which secret wire format a client speaks. */\nexport const FORMAT_KEY = 'secret_format'\n\n/** Wire format published and understood by this SDK. */\nexport const FORMAT_REF = 'ref'\n\n/** One `$secret` marker as published by a settings response. */\nexport interface PluginSecretRef {\n $secret: string | null\n set?: boolean\n locked?: boolean\n}\n\n/** What a settings form should tell the user about one secret field. */\nexport type PluginSecretState = 'set' | 'unset' | 'environment'\n\nconst MARKER_KEYS = new Set([REF_KEY, 'set', 'locked'])\n\n/** Return whether one settings value is a `$secret` reference marker. */\nexport function isRef(value: unknown): value is PluginSecretRef {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const record = value as Record<string, unknown>\n if (!(REF_KEY in record)) return false\n return Object.keys(record).every(key => MARKER_KEYS.has(key))\n}\n\n/** Return the stored secret id behind a marker, or `null` when nothing is stored. */\nexport function id(value: unknown): string | null {\n if (!isRef(value)) return null\n return typeof value.$secret === 'string' ? value.$secret : null\n}\n\n/** Classify one secret field for display: stored, unset, or environment-provided. */\nexport function state(value: unknown): PluginSecretState {\n if (isRef(value)) {\n if (value.locked) return 'environment'\n return typeof value.$secret === 'string' ? 'set' : 'unset'\n }\n return typeof value === 'string' && value.length > 0 ? 'set' : 'unset'\n}\n\n/** Human label for one secret field's state. */\nexport function label(value: unknown): string {\n const current = state(value)\n if (current === 'environment') return 'Provided by environment'\n return current === 'set' ? 'Set' : 'Not set'\n}\n\n/** Whether a secret field is read-only because the environment supplies it. */\nexport function isLocked(value: unknown): boolean {\n return isRef(value) && value.locked === true\n}\n\n/**\n * Value to submit for an untouched secret field: the reference, unchanged.\n *\n * A locked marker round-trips too, which is how the platform keeps a stored\n * value that an environment variable currently hides.\n */\nexport function keep(current: unknown): PluginSecretRef | null {\n if (isRef(current)) return { ...current }\n return null\n}\n\n/** Value to submit when the user typed a new secret. */\nexport function set(value: string): string {\n return value\n}\n\n/** Value to submit when the user cleared a secret. */\nexport function clear(): null {\n return null\n}\n\n/** Whether a settings response declares the `$secret` reference wire format. */\nexport function usesReferences(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false\n return (\n (response as Record<string, unknown>)[FORMAT_KEY]\n === FORMAT_REF\n )\n}\n","<script setup lang=\"ts\">\n/** Edits one plugin secret setting: shows set / not set / provided by environment, and submits a `$secret` reference, a new value, or `null`. */\nimport { computed, ref, watch } from 'vue'\nimport BaseInput from './BaseInput.vue'\nimport BaseButton from './BaseButton.vue'\nimport * as pluginSecret from '../utils/pluginSecrets'\nimport type { PluginSecretRef, PluginSecretState } from '../utils/pluginSecrets'\n\ntype SecretValue = PluginSecretRef | string | null\n\ninterface Props {\n /** The `$secret` marker from the settings response, a typed string, or `null`. */\n modelValue?: SecretValue\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** Label on the control that starts entering a replacement value. */\n changeLabel?: string\n /** Label on the control that clears a stored secret. */\n clearLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: null,\n placeholder: 'Enter a new value',\n disabled: false,\n invalid: false,\n size: 'md',\n changeLabel: 'Change',\n clearLabel: 'Clear',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: SecretValue]\n}>()\n\n/** The reference this field started from, so an abandoned edit can restore it. */\nconst storedReference = ref<PluginSecretRef | null>(pluginSecret.keep(props.modelValue))\nconst isEditing = ref(typeof props.modelValue === 'string')\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (pluginSecret.isRef(value)) {\n storedReference.value = pluginSecret.keep(value)\n isEditing.value = false\n }\n },\n)\n\nconst state = computed<PluginSecretState>(() => pluginSecret.state(props.modelValue))\nconst locked = computed(() => pluginSecret.isLocked(props.modelValue)\n || pluginSecret.isLocked(storedReference.value))\nconst statusLabel = computed(() => isEditing.value\n ? 'New value'\n : pluginSecret.label(props.modelValue))\nconst typedValue = computed(() => typeof props.modelValue === 'string' ? props.modelValue : '')\nconst canClear = computed(() => !locked.value && (state.value === 'set' || isEditing.value))\n\nfunction startEditing(): void {\n if (props.disabled || locked.value) return\n isEditing.value = true\n emit('update:modelValue', pluginSecret.set(''))\n}\n\nfunction updateTyped(value: string | number | null): void {\n emit('update:modelValue', pluginSecret.set(value == null ? '' : String(value)))\n}\n\nfunction cancelEditing(): void {\n isEditing.value = false\n emit('update:modelValue', storedReference.value ? { ...storedReference.value } : null)\n}\n\nfunction clear(): void {\n if (props.disabled || locked.value) return\n isEditing.value = false\n storedReference.value = null\n emit('update:modelValue', pluginSecret.clear())\n}\n</script>\n\n<template>\n <div class=\"mint-secret-input\" :class=\"{ 'mint-secret-input--error': invalid }\">\n <div class=\"mint-secret-input__status\">\n <span\n class=\"mint-secret-input__badge\"\n :class=\"`mint-secret-input__badge--${isEditing ? 'pending' : state}`\"\n ><span class=\"mint-secret-input__dot\" aria-hidden=\"true\" />{{ statusLabel }}</span>\n <span v-if=\"locked\" class=\"mint-secret-input__hint\">\n This value comes from the environment and cannot be edited here.\n </span>\n </div>\n\n <BaseInput\n v-if=\"isEditing\"\n type=\"password\"\n autocomplete=\"new-password\"\n :model-value=\"typedValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n @update:model-value=\"updateTyped\"\n />\n\n <div class=\"mint-secret-input__actions\">\n <BaseButton\n v-if=\"!isEditing\"\n type=\"button\"\n variant=\"secondary\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled || locked\"\n @click=\"startEditing\"\n >\n {{ changeLabel }}\n </BaseButton>\n <BaseButton\n v-else\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"cancelEditing\"\n >\n Cancel\n </BaseButton>\n <BaseButton\n v-if=\"canClear\"\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Edits one plugin secret setting: shows set / not set / provided by environment, and submits a `$secret` reference, a new value, or `null`. */\nimport { computed, ref, watch } from 'vue'\nimport BaseInput from './BaseInput.vue'\nimport BaseButton from './BaseButton.vue'\nimport * as pluginSecret from '../utils/pluginSecrets'\nimport type { PluginSecretRef, PluginSecretState } from '../utils/pluginSecrets'\n\ntype SecretValue = PluginSecretRef | string | null\n\ninterface Props {\n /** The `$secret` marker from the settings response, a typed string, or `null`. */\n modelValue?: SecretValue\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n /** Label on the control that starts entering a replacement value. */\n changeLabel?: string\n /** Label on the control that clears a stored secret. */\n clearLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: null,\n placeholder: 'Enter a new value',\n disabled: false,\n invalid: false,\n size: 'md',\n changeLabel: 'Change',\n clearLabel: 'Clear',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: SecretValue]\n}>()\n\n/** The reference this field started from, so an abandoned edit can restore it. */\nconst storedReference = ref<PluginSecretRef | null>(pluginSecret.keep(props.modelValue))\nconst isEditing = ref(typeof props.modelValue === 'string')\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (pluginSecret.isRef(value)) {\n storedReference.value = pluginSecret.keep(value)\n isEditing.value = false\n }\n },\n)\n\nconst state = computed<PluginSecretState>(() => pluginSecret.state(props.modelValue))\nconst locked = computed(() => pluginSecret.isLocked(props.modelValue)\n || pluginSecret.isLocked(storedReference.value))\nconst statusLabel = computed(() => isEditing.value\n ? 'New value'\n : pluginSecret.label(props.modelValue))\nconst typedValue = computed(() => typeof props.modelValue === 'string' ? props.modelValue : '')\nconst canClear = computed(() => !locked.value && (state.value === 'set' || isEditing.value))\n\nfunction startEditing(): void {\n if (props.disabled || locked.value) return\n isEditing.value = true\n emit('update:modelValue', pluginSecret.set(''))\n}\n\nfunction updateTyped(value: string | number | null): void {\n emit('update:modelValue', pluginSecret.set(value == null ? '' : String(value)))\n}\n\nfunction cancelEditing(): void {\n isEditing.value = false\n emit('update:modelValue', storedReference.value ? { ...storedReference.value } : null)\n}\n\nfunction clear(): void {\n if (props.disabled || locked.value) return\n isEditing.value = false\n storedReference.value = null\n emit('update:modelValue', pluginSecret.clear())\n}\n</script>\n\n<template>\n <div class=\"mint-secret-input\" :class=\"{ 'mint-secret-input--error': invalid }\">\n <div class=\"mint-secret-input__status\">\n <span\n class=\"mint-secret-input__badge\"\n :class=\"`mint-secret-input__badge--${isEditing ? 'pending' : state}`\"\n ><span class=\"mint-secret-input__dot\" aria-hidden=\"true\" />{{ statusLabel }}</span>\n <span v-if=\"locked\" class=\"mint-secret-input__hint\">\n This value comes from the environment and cannot be edited here.\n </span>\n </div>\n\n <BaseInput\n v-if=\"isEditing\"\n type=\"password\"\n autocomplete=\"new-password\"\n :model-value=\"typedValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :invalid=\"invalid\"\n :size=\"size\"\n @update:model-value=\"updateTyped\"\n />\n\n <div class=\"mint-secret-input__actions\">\n <BaseButton\n v-if=\"!isEditing\"\n type=\"button\"\n variant=\"secondary\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled || locked\"\n @click=\"startEditing\"\n >\n {{ changeLabel }}\n </BaseButton>\n <BaseButton\n v-else\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"cancelEditing\"\n >\n Cancel\n </BaseButton>\n <BaseButton\n v-if=\"canClear\"\n type=\"button\"\n variant=\"ghost\"\n :size=\"size === 'lg' ? 'md' : 'sm'\"\n :disabled=\"disabled\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Lets users type and add tags with autocomplete suggestions, categories, and a max-tag cap. */\nimport { ref, computed, useTemplateRef } from 'vue'\nimport { useSelectionLimit } from '../composables/useSelectionLimit'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport type { Tone } from '../types'\n\ninterface TagSuggestion {\n value: string\n count?: number\n}\n\ninterface TagCategory {\n name: string\n prefix: string\n tone?: Tone\n}\n\ninterface Props {\n modelValue?: string[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n maxTags?: number\n allowDuplicates?: boolean\n suggestions?: string[] | TagSuggestion[]\n categories?: TagCategory[]\n activeCategory?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n disabled: false,\n invalid: false,\n size: 'md',\n allowDuplicates: false,\n suggestions: () => [],\n categories: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n 'update:activeCategory': [prefix: string]\n}>()\n\nconst inputValue = ref('')\nconst highlightedIndex = ref(-1)\n// The text input doubles as the dropdown trigger, so focus restoration is the\n// composable's `triggerRef` rather than a component-local refocus helper.\nconst {\n isOpen: dropdownOpen,\n triggerRef: inputRef,\n open: openDropdown,\n close: closeDropdown,\n} = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('root'),\n onClose: () => {\n highlightedIndex.value = -1\n },\n})\n\nconst selectionLimit = useSelectionLimit({\n count: () => props.modelValue.length,\n max: () => props.maxTags,\n})\nconst canAddMore = selectionLimit.canAddMore\n\nconst normalizedSuggestions = computed<TagSuggestion[]>(() => {\n return props.suggestions.map(s => typeof s === 'string' ? { value: s } : s)\n})\n\nconst filteredSuggestions = computed<TagSuggestion[]>(() => {\n const q = inputValue.value.trim().toLowerCase()\n if (!q) return []\n return normalizedSuggestions.value\n .filter(s => s.value.toLowerCase().startsWith(q) && !props.modelValue.includes(s.value))\n .slice(0, 8)\n})\n\nfunction categoryFor(tag: string): TagCategory | undefined {\n const colonIdx = tag.indexOf(':')\n if (colonIdx === -1) return undefined\n const prefix = tag.slice(0, colonIdx)\n return props.categories.find(c => c.prefix === prefix)\n}\n\n// 3f: a category is shown by a group-color dot (3a palette), never a semantic tint.\nconst GROUP_COLORS = [\n 'var(--mint-sample-1)', 'var(--mint-sample-2)', 'var(--mint-sample-3)', 'var(--mint-sample-4)',\n 'var(--mint-sample-5)', 'var(--mint-sample-6)', 'var(--mint-sample-7)', 'var(--mint-sample-8)',\n]\n\nfunction groupColor(category: TagCategory): string {\n return GROUP_COLORS[props.categories.indexOf(category) % GROUP_COLORS.length]\n}\n\nfunction addTag(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return\n if (!selectionLimit.canAdd()) return\n\n // If a category is active and user didn't already type a prefix, prepend it\n let final = trimmed\n if (props.activeCategory && !trimmed.includes(':')) {\n final = `${props.activeCategory}:${trimmed}`\n }\n\n if (!props.allowDuplicates && props.modelValue.includes(final)) return\n\n emit('update:modelValue', [...props.modelValue, final])\n inputValue.value = ''\n closeDropdown()\n}\n\nfunction removeTag(index: number) {\n if (props.disabled) return\n const newTags = [...props.modelValue]\n newTags.splice(index, 1)\n emit('update:modelValue', newTags)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'ArrowDown' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.min(highlightedIndex.value + 1, filteredSuggestions.value.length - 1)\n openDropdown()\n return\n }\n if (event.key === 'ArrowUp' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)\n return\n }\n if (event.key === 'Enter' || event.key === ',') {\n event.preventDefault()\n if (highlightedIndex.value >= 0 && filteredSuggestions.value[highlightedIndex.value]) {\n addTag(filteredSuggestions.value[highlightedIndex.value].value)\n } else {\n addTag(inputValue.value)\n }\n return\n }\n if (event.key === 'Escape') {\n closeDropdown(true)\n return\n }\n if (event.key === 'Backspace' && !inputValue.value && props.modelValue.length > 0) {\n removeTag(props.modelValue.length - 1)\n }\n}\n\nfunction handleFocus() {\n if (filteredSuggestions.value.length) openDropdown()\n}\n\nfunction handleBlur() {\n // Delay so a click on a suggestion fires first\n setTimeout(() => {\n closeDropdown()\n }, 120)\n}\n\nfunction handlePaste(event: ClipboardEvent) {\n event.preventDefault()\n const text = event.clipboardData?.getData('text')\n if (!text) return\n\n const tags = text.split(/[,\\n]/).map(t => t.trim()).filter(Boolean)\n const newTags = [...props.modelValue]\n\n for (const tag of tags) {\n if (!selectionLimit.canAdd(1, newTags.length)) break\n if (!props.allowDuplicates && newTags.includes(tag)) continue\n newTags.push(tag)\n }\n\n emit('update:modelValue', newTags)\n}\n\nfunction focusInput() {\n inputRef.value?.focus()\n}\n\nfunction setCategory(prefix: string) {\n emit('update:activeCategory', prefix === props.activeCategory ? '' : prefix)\n}\n\nfunction onInputEvent() {\n if (filteredSuggestions.value.length > 0) {\n openDropdown()\n } else {\n closeDropdown()\n }\n highlightedIndex.value = -1\n}\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"[\n 'mint-tags-input',\n `mint-tags-input--${size}`,\n invalid ? 'mint-tags-input--error' : '',\n disabled ? 'mint-tags-input--disabled' : '',\n categories.length ? 'mint-tags-input--categorized' : '',\n ]\"\n >\n <!-- Category switcher (only if categories defined) -->\n <div v-if=\"categories.length\" class=\"mint-tags-input__categories\">\n <button\n v-for=\"cat in categories\"\n :key=\"cat.prefix\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__category',\n `mint-tags-input__category--${cat.tone ?? 'neutral'}`,\n activeCategory === cat.prefix ? 'mint-tags-input__category--active' : '',\n ]\"\n :disabled=\"disabled\"\n @click=\"setCategory(cat.prefix)\"\n >\n <span class=\"mint-tags-input__tag-dot\" :style=\"{ background: groupColor(cat) }\" aria-hidden=\"true\" />\n {{ cat.name }}\n </button>\n </div>\n\n <div class=\"mint-tags-input__field\" @click=\"focusInput\">\n <span\n v-for=\"(tag, index) in modelValue\"\n :key=\"`${tag}-${index}`\"\n :class=\"[\n 'mint-tags-input__tag',\n `mint-tags-input__tag--${size}`,\n categoryFor(tag) ? `mint-tags-input__tag--${categoryFor(tag)?.tone ?? 'neutral'}` : '',\n ]\"\n >\n <span\n v-if=\"categoryFor(tag)\"\n class=\"mint-tags-input__tag-dot\"\n :style=\"{ background: groupColor(categoryFor(tag)!) }\"\n aria-hidden=\"true\"\n />\n {{ tag }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n :aria-label=\"`Remove ${tag}`\"\n class=\"mint-tags-input__tag-remove\"\n @click.stop=\"removeTag(index)\"\n >\n <svg class=\"mint-tags-input__tag-remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n\n <input\n ref=\"inputRef\"\n v-model=\"inputValue\"\n type=\"text\"\n :placeholder=\"modelValue.length === 0 ? placeholder : ''\"\n :disabled=\"disabled || !canAddMore\"\n :class=\"['mint-tags-input__input', `mint-tags-input__input--${size}`]\"\n @keydown=\"handleKeydown\"\n @paste=\"handlePaste\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n @input=\"onInputEvent\"\n />\n\n <!-- Autocomplete dropdown -->\n <div\n v-if=\"dropdownOpen && filteredSuggestions.length\"\n class=\"mint-tags-input__dropdown\"\n >\n <button\n v-for=\"(sug, i) in filteredSuggestions\"\n :key=\"sug.value\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__dropdown-item',\n i === highlightedIndex ? 'mint-tags-input__dropdown-item--highlighted' : '',\n ]\"\n @mousedown.prevent=\"addTag(sug.value)\"\n >\n <span>{{ sug.value }}</span>\n <span v-if=\"sug.count !== undefined\" class=\"mint-tags-input__dropdown-count\">\n {{ sug.count }}\n </span>\n </button>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Lets users type and add tags with autocomplete suggestions, categories, and a max-tag cap. */\nimport { ref, computed, useTemplateRef } from 'vue'\nimport { useSelectionLimit } from '../composables/useSelectionLimit'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport type { Tone } from '../types'\n\ninterface TagSuggestion {\n value: string\n count?: number\n}\n\ninterface TagCategory {\n name: string\n prefix: string\n tone?: Tone\n}\n\ninterface Props {\n modelValue?: string[]\n placeholder?: string\n disabled?: boolean\n invalid?: boolean\n size?: 'sm' | 'md' | 'lg'\n maxTags?: number\n allowDuplicates?: boolean\n suggestions?: string[] | TagSuggestion[]\n categories?: TagCategory[]\n activeCategory?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n disabled: false,\n invalid: false,\n size: 'md',\n allowDuplicates: false,\n suggestions: () => [],\n categories: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n 'update:activeCategory': [prefix: string]\n}>()\n\nconst inputValue = ref('')\nconst highlightedIndex = ref(-1)\n// The text input doubles as the dropdown trigger, so focus restoration is the\n// composable's `triggerRef` rather than a component-local refocus helper.\nconst {\n isOpen: dropdownOpen,\n triggerRef: inputRef,\n open: openDropdown,\n close: closeDropdown,\n} = useDropdownState({\n rootRef: useTemplateRef<HTMLElement>('root'),\n onClose: () => {\n highlightedIndex.value = -1\n },\n})\n\nconst selectionLimit = useSelectionLimit({\n count: () => props.modelValue.length,\n max: () => props.maxTags,\n})\nconst canAddMore = selectionLimit.canAddMore\n\nconst normalizedSuggestions = computed<TagSuggestion[]>(() => {\n return props.suggestions.map(s => typeof s === 'string' ? { value: s } : s)\n})\n\nconst filteredSuggestions = computed<TagSuggestion[]>(() => {\n const q = inputValue.value.trim().toLowerCase()\n if (!q) return []\n return normalizedSuggestions.value\n .filter(s => s.value.toLowerCase().startsWith(q) && !props.modelValue.includes(s.value))\n .slice(0, 8)\n})\n\nfunction categoryFor(tag: string): TagCategory | undefined {\n const colonIdx = tag.indexOf(':')\n if (colonIdx === -1) return undefined\n const prefix = tag.slice(0, colonIdx)\n return props.categories.find(c => c.prefix === prefix)\n}\n\n// 3f: a category is shown by a group-color dot (3a palette), never a semantic tint.\nconst GROUP_COLORS = [\n 'var(--mint-sample-1)', 'var(--mint-sample-2)', 'var(--mint-sample-3)', 'var(--mint-sample-4)',\n 'var(--mint-sample-5)', 'var(--mint-sample-6)', 'var(--mint-sample-7)', 'var(--mint-sample-8)',\n]\n\nfunction groupColor(category: TagCategory): string {\n return GROUP_COLORS[props.categories.indexOf(category) % GROUP_COLORS.length]\n}\n\nfunction addTag(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return\n if (!selectionLimit.canAdd()) return\n\n // If a category is active and user didn't already type a prefix, prepend it\n let final = trimmed\n if (props.activeCategory && !trimmed.includes(':')) {\n final = `${props.activeCategory}:${trimmed}`\n }\n\n if (!props.allowDuplicates && props.modelValue.includes(final)) return\n\n emit('update:modelValue', [...props.modelValue, final])\n inputValue.value = ''\n closeDropdown()\n}\n\nfunction removeTag(index: number) {\n if (props.disabled) return\n const newTags = [...props.modelValue]\n newTags.splice(index, 1)\n emit('update:modelValue', newTags)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'ArrowDown' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.min(highlightedIndex.value + 1, filteredSuggestions.value.length - 1)\n openDropdown()\n return\n }\n if (event.key === 'ArrowUp' && filteredSuggestions.value.length) {\n event.preventDefault()\n highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)\n return\n }\n if (event.key === 'Enter' || event.key === ',') {\n event.preventDefault()\n if (highlightedIndex.value >= 0 && filteredSuggestions.value[highlightedIndex.value]) {\n addTag(filteredSuggestions.value[highlightedIndex.value].value)\n } else {\n addTag(inputValue.value)\n }\n return\n }\n if (event.key === 'Escape') {\n closeDropdown(true)\n return\n }\n if (event.key === 'Backspace' && !inputValue.value && props.modelValue.length > 0) {\n removeTag(props.modelValue.length - 1)\n }\n}\n\nfunction handleFocus() {\n if (filteredSuggestions.value.length) openDropdown()\n}\n\nfunction handleBlur() {\n // Delay so a click on a suggestion fires first\n setTimeout(() => {\n closeDropdown()\n }, 120)\n}\n\nfunction handlePaste(event: ClipboardEvent) {\n event.preventDefault()\n const text = event.clipboardData?.getData('text')\n if (!text) return\n\n const tags = text.split(/[,\\n]/).map(t => t.trim()).filter(Boolean)\n const newTags = [...props.modelValue]\n\n for (const tag of tags) {\n if (!selectionLimit.canAdd(1, newTags.length)) break\n if (!props.allowDuplicates && newTags.includes(tag)) continue\n newTags.push(tag)\n }\n\n emit('update:modelValue', newTags)\n}\n\nfunction focusInput() {\n inputRef.value?.focus()\n}\n\nfunction setCategory(prefix: string) {\n emit('update:activeCategory', prefix === props.activeCategory ? '' : prefix)\n}\n\nfunction onInputEvent() {\n if (filteredSuggestions.value.length > 0) {\n openDropdown()\n } else {\n closeDropdown()\n }\n highlightedIndex.value = -1\n}\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"[\n 'mint-tags-input',\n `mint-tags-input--${size}`,\n invalid ? 'mint-tags-input--error' : '',\n disabled ? 'mint-tags-input--disabled' : '',\n categories.length ? 'mint-tags-input--categorized' : '',\n ]\"\n >\n <!-- Category switcher (only if categories defined) -->\n <div v-if=\"categories.length\" class=\"mint-tags-input__categories\">\n <button\n v-for=\"cat in categories\"\n :key=\"cat.prefix\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__category',\n `mint-tags-input__category--${cat.tone ?? 'neutral'}`,\n activeCategory === cat.prefix ? 'mint-tags-input__category--active' : '',\n ]\"\n :disabled=\"disabled\"\n @click=\"setCategory(cat.prefix)\"\n >\n <span class=\"mint-tags-input__tag-dot\" :style=\"{ background: groupColor(cat) }\" aria-hidden=\"true\" />\n {{ cat.name }}\n </button>\n </div>\n\n <div class=\"mint-tags-input__field\" @click=\"focusInput\">\n <span\n v-for=\"(tag, index) in modelValue\"\n :key=\"`${tag}-${index}`\"\n :class=\"[\n 'mint-tags-input__tag',\n `mint-tags-input__tag--${size}`,\n categoryFor(tag) ? `mint-tags-input__tag--${categoryFor(tag)?.tone ?? 'neutral'}` : '',\n ]\"\n >\n <span\n v-if=\"categoryFor(tag)\"\n class=\"mint-tags-input__tag-dot\"\n :style=\"{ background: groupColor(categoryFor(tag)!) }\"\n aria-hidden=\"true\"\n />\n {{ tag }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n :aria-label=\"`Remove ${tag}`\"\n class=\"mint-tags-input__tag-remove\"\n @click.stop=\"removeTag(index)\"\n >\n <svg class=\"mint-tags-input__tag-remove-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </span>\n\n <input\n ref=\"inputRef\"\n v-model=\"inputValue\"\n type=\"text\"\n :placeholder=\"modelValue.length === 0 ? placeholder : ''\"\n :disabled=\"disabled || !canAddMore\"\n :class=\"['mint-tags-input__input', `mint-tags-input__input--${size}`]\"\n @keydown=\"handleKeydown\"\n @paste=\"handlePaste\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n @input=\"onInputEvent\"\n />\n\n <!-- Autocomplete dropdown -->\n <div\n v-if=\"dropdownOpen && filteredSuggestions.length\"\n class=\"mint-tags-input__dropdown\"\n >\n <button\n v-for=\"(sug, i) in filteredSuggestions\"\n :key=\"sug.value\"\n type=\"button\"\n :class=\"[\n 'mint-tags-input__dropdown-item',\n i === highlightedIndex ? 'mint-tags-input__dropdown-item--highlighted' : '',\n ]\"\n @mousedown.prevent=\"addTag(sug.value)\"\n >\n <span>{{ sug.value }}</span>\n <span v-if=\"sug.count !== undefined\" class=\"mint-tags-input__dropdown-count\">\n {{ sug.count }}\n </span>\n </button>\n </div>\n </div>\n </div>\n</template>\n","import type { PlatformContext } from '../types'\n\nexport function getInjectedPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\n/** Return the platform's canonical plugin identity for the mounted frontend. */\nexport function resolveCurrentPluginId(): string | undefined {\n const pluginId = getInjectedPlatformContext()?.plugin?.id\n return typeof pluginId === 'string' && pluginId ? pluginId : undefined\n}\n\nexport function parseExperimentId(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n if (value && typeof value === 'object' && 'id' in value) {\n return parseExperimentId((value as { id?: unknown }).id)\n }\n return undefined\n}\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable single-select list shared by the experiment and\n * artifact selector modals: two-line rows (title, then code + meta) with status and date\n * in a right-hand column, a filled selected row, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, ref, useId, watch } from 'vue'\nimport { Check } from 'lucide-vue-next'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\nimport type { Tone } from '../../types'\n\nexport interface ResourcePickerRow {\n /** Identifier shown as a gray pill at the start of the second line, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts after the code, joined with \" · \". */\n meta?: string[]\n /** Right column, above the date, tinted by its tone. */\n status?: { label: string; tone: Tone }\n /** Right column, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n /** Focus the search field when the list mounts (the modal's focus trap honours `autofocus`). */\n autofocusSearch?: boolean\n }>(),\n {\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst indexByKey = computed(() => new Map(props.items.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = props.items[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = props.items\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => props.items,\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n :autofocus=\"autofocusSearch\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <div\n v-for=\"item in items\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\">{{ describe(item).title }}</span>\n <span v-if=\"describe(item).code || describe(item).meta?.length\" class=\"mint-resource-picker__meta\"\n ><span v-if=\"describe(item).code\" class=\"mint-resource-picker__code mint-exp-code mint-exp-code--sm\">{{\n describe(item).code\n }}</span\n ><span v-if=\"describe(item).meta?.length\">{{ describe(item).meta!.join(' · ') }}</span></span\n >\n </span>\n <span v-if=\"describe(item).status || describe(item).date\" class=\"mint-resource-picker__aside\">\n <span\n v-if=\"describe(item).status\"\n class=\"mint-resource-picker__status\"\n :class=\"`mint-resource-picker__status--${describe(item).status!.tone}`\"\n >{{ describe(item).status!.label }}</span\n >\n <span v-if=\"describe(item).date\" class=\"mint-resource-picker__date\">{{ describe(item).date }}</span>\n </span>\n <Check\n v-if=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__check\"\n :size=\"14\"\n :stroke-width=\"2\"\n aria-hidden=\"true\"\n />\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable single-select list shared by the experiment and\n * artifact selector modals: two-line rows (title, then code + meta) with status and date\n * in a right-hand column, a filled selected row, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, ref, useId, watch } from 'vue'\nimport { Check } from 'lucide-vue-next'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\nimport type { Tone } from '../../types'\n\nexport interface ResourcePickerRow {\n /** Identifier shown as a gray pill at the start of the second line, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts after the code, joined with \" · \". */\n meta?: string[]\n /** Right column, above the date, tinted by its tone. */\n status?: { label: string; tone: Tone }\n /** Right column, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n /** Focus the search field when the list mounts (the modal's focus trap honours `autofocus`). */\n autofocusSearch?: boolean\n }>(),\n {\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst indexByKey = computed(() => new Map(props.items.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = props.items[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = props.items\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => props.items,\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n :autofocus=\"autofocusSearch\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <div\n v-for=\"item in items\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\">{{ describe(item).title }}</span>\n <span v-if=\"describe(item).code || describe(item).meta?.length\" class=\"mint-resource-picker__meta\"\n ><span v-if=\"describe(item).code\" class=\"mint-resource-picker__code mint-exp-code mint-exp-code--sm\">{{\n describe(item).code\n }}</span\n ><span v-if=\"describe(item).meta?.length\">{{ describe(item).meta!.join(' · ') }}</span></span\n >\n </span>\n <span v-if=\"describe(item).status || describe(item).date\" class=\"mint-resource-picker__aside\">\n <span\n v-if=\"describe(item).status\"\n class=\"mint-resource-picker__status\"\n :class=\"`mint-resource-picker__status--${describe(item).status!.tone}`\"\n >{{ describe(item).status!.label }}</span\n >\n <span v-if=\"describe(item).date\" class=\"mint-resource-picker__date\">{{ describe(item).date }}</span>\n </span>\n <Check\n v-if=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__check\"\n :size=\"14\"\n :stroke-width=\"2\"\n aria-hidden=\"true\"\n />\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n </div>\n </div>\n </div>\n</template>\n","/** Narrow an unknown value to a plain object (arrays and null excluded). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],"mappings":"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"}