@morscherlab/mint-sdk 1.4.0-beta.9 → 1.4.0

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 (198) hide show
  1. package/README.md +14 -3
  2. package/dist/{AlertBox-B2Bgr3ei.js → AlertBox-DwgNTEqf.js} +3 -3
  3. package/dist/{AlertBox-B2Bgr3ei.js.map → AlertBox-DwgNTEqf.js.map} +1 -1
  4. package/dist/{AppSidebar-Dq9W1jE2.js → AppSidebar-CZZaxni0.js} +1103 -144
  5. package/dist/AppSidebar-CZZaxni0.js.map +1 -0
  6. package/dist/{ConfirmDialog-nbJj51is.js → ConfirmDialog-CjWoxAD1.js} +2 -2
  7. package/dist/{ConfirmDialog-nbJj51is.js.map → ConfirmDialog-CjWoxAD1.js.map} +1 -1
  8. package/dist/{ExperimentPopover-5T1fAq2L.js → ExperimentPopover-DujiuQIO.js} +5 -5
  9. package/dist/{ExperimentPopover-5T1fAq2L.js.map → ExperimentPopover-DujiuQIO.js.map} +1 -1
  10. package/dist/{ExperimentSelectorModal-65peG4Up.js → ExperimentSelectorModal-B4j4eUOJ.js} +114 -98
  11. package/dist/ExperimentSelectorModal-B4j4eUOJ.js.map +1 -0
  12. package/dist/{SegmentedControl-BtnnjWzs.js → SegmentedControl-DyUPH3I5.js} +2 -2
  13. package/dist/{SegmentedControl-BtnnjWzs.js.map → SegmentedControl-DyUPH3I5.js.map} +1 -1
  14. package/dist/{SettingsModal-483nyI6b.js → SettingsModal-D2MOOtuO.js} +26 -25
  15. package/dist/SettingsModal-D2MOOtuO.js.map +1 -0
  16. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  17. package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
  18. package/dist/__tests__/components/FloatingPanelsInModal.test.d.ts +1 -0
  19. package/dist/__tests__/composables/useFloatingPanel.test.d.ts +1 -0
  20. package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
  21. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  22. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  23. package/dist/components/AppTopBar.vue.d.ts +20 -5
  24. package/dist/components/BaseButton.vue.d.ts +4 -2
  25. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -1
  26. package/dist/components/JobsStatusTray.vue.d.ts +15 -4
  27. package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
  28. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
  29. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -3
  30. package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
  31. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  32. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +2 -2
  33. package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
  34. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
  35. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  36. package/dist/composables/useFileImport.d.ts +7 -0
  37. package/dist/composables/useFloatingPanel.d.ts +29 -0
  38. package/dist/composables/useJobCenter.d.ts +41 -3
  39. package/dist/composables/useOnboarding.d.ts +119 -0
  40. package/dist/{controlSchemaModel-B8CTXagP.js → controlSchemaModel-Bsg0t5Ab.js} +2 -2
  41. package/dist/{controlSchemaModel-B8CTXagP.js.map → controlSchemaModel-Bsg0t5Ab.js.map} +1 -1
  42. package/dist/{data-CgILxDLW.js → data-Boeh4uPI.js} +13 -12
  43. package/dist/{data-CgILxDLW.js.map → data-Boeh4uPI.js.map} +1 -1
  44. package/dist/data.d.ts +1 -1
  45. package/dist/data.js +9 -9
  46. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  47. package/dist/experiment-DyO54FQB.js.map +1 -0
  48. package/dist/{experimentStatus-Cqp6qNrR.js → experimentStatus-DCn2QKG7.js} +2 -2
  49. package/dist/{experimentStatus-Cqp6qNrR.js.map → experimentStatus-DCn2QKG7.js.map} +1 -1
  50. package/dist/index.js +20 -20
  51. package/dist/{install-BtLWTk6H.js → install-BEHp7Mo-.js} +15 -15
  52. package/dist/{install-BtLWTk6H.js.map → install-BEHp7Mo-.js.map} +1 -1
  53. package/dist/install.js +1 -1
  54. package/dist/{lab-MHzp-_J8.js → lab-D61eaX6f.js} +68 -61
  55. package/dist/{lab-MHzp-_J8.js.map → lab-D61eaX6f.js.map} +1 -1
  56. package/dist/lab.js +4 -4
  57. package/dist/{records-B6gpM_3e.js → records-D4aQXyZu.js} +193 -133
  58. package/dist/records-D4aQXyZu.js.map +1 -0
  59. package/dist/{runtime-7vfl_bI3.js → runtime-q-R0CNLh.js} +400 -33
  60. package/dist/runtime-q-R0CNLh.js.map +1 -0
  61. package/dist/runtime.d.ts +1 -1
  62. package/dist/runtime.js +7 -7
  63. package/dist/{shell-Cs9OJMnm.js → shell-6CGFvUUw.js} +10 -5
  64. package/dist/{shell-Cs9OJMnm.js.map → shell-6CGFvUUw.js.map} +1 -1
  65. package/dist/shell.d.ts +1 -0
  66. package/dist/shell.js +6 -6
  67. package/dist/stores/index.d.ts +1 -1
  68. package/dist/stores/index.js +2 -2
  69. package/dist/stores/settings.d.ts +4 -12
  70. package/dist/styles.css +1191 -479
  71. package/dist/types/components.d.ts +2 -0
  72. package/dist/types/index.d.ts +1 -1
  73. package/dist/types/jobs.d.ts +9 -0
  74. package/dist/types/platform.d.ts +1 -1
  75. package/dist/{useDropdownState-8yWMu-7_.js → useDropdownState-uFIz6Yv8.js} +16 -4
  76. package/dist/useDropdownState-uFIz6Yv8.js.map +1 -0
  77. package/dist/{useExperimentSamples-DHnxKFAF.js → useExperimentSamples-QEFoq4tf.js} +48 -6
  78. package/dist/useExperimentSamples-QEFoq4tf.js.map +1 -0
  79. package/dist/{useListReorder-BitdUhxn.js → useListReorder-DsuzwWGS.js} +122 -172
  80. package/dist/useListReorder-DsuzwWGS.js.map +1 -0
  81. package/dist/{useRackEditor-DiwCt77M.js → useRackEditor-KpZ4iJ6o.js} +22 -32
  82. package/dist/useRackEditor-KpZ4iJ6o.js.map +1 -0
  83. package/dist/useRealtime-B58Lo-Tm.js +508 -0
  84. package/dist/useRealtime-B58Lo-Tm.js.map +1 -0
  85. package/dist/{useRequest-D506eHi8.js → useRequest-BuDmW8Jc.js} +8 -37
  86. package/dist/useRequest-BuDmW8Jc.js.map +1 -0
  87. package/package.json +3 -2
  88. package/src/__stories__/experiment-helpers.ts +3 -3
  89. package/src/__tests__/components/ActionMenu.test.ts +2 -2
  90. package/src/__tests__/components/AppTopBar.test.ts +206 -1
  91. package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
  92. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  93. package/src/__tests__/components/BaseButton.test.ts +19 -0
  94. package/src/__tests__/components/BaseModal.test.ts +13 -0
  95. package/src/__tests__/components/ExperimentSelectorModal.test.ts +34 -1
  96. package/src/__tests__/components/FloatingPanelsInModal.test.ts +94 -0
  97. package/src/__tests__/components/GeneratedPluginView.test.ts +1 -1
  98. package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
  99. package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
  100. package/src/__tests__/components/SampleSelector.test.ts +20 -0
  101. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  102. package/src/__tests__/composables/useFileImport.test.ts +36 -0
  103. package/src/__tests__/composables/useFloatingPanel.test.ts +68 -0
  104. package/src/__tests__/composables/useJobCenter.test.ts +262 -3
  105. package/src/__tests__/composables/useOnboarding.test.ts +317 -0
  106. package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
  107. package/src/__tests__/fixtures/table-import/cells.xlsx +0 -0
  108. package/src/__tests__/fixtures/table-import/samples.xlsx +0 -0
  109. package/src/__tests__/stores/settings.test.ts +21 -21
  110. package/src/__tests__/styles/cssTokens.test.ts +4 -1
  111. package/src/__tests__/styles/menusShellRefresh.test.ts +8 -2
  112. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  113. package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
  114. package/src/components/ActionMenu.vue +6 -37
  115. package/src/components/AppTopBar.onboarding.story.vue +69 -0
  116. package/src/components/AppTopBar.story.vue +59 -4
  117. package/src/components/AppTopBar.vue +132 -10
  118. package/src/components/BaseButton.vue +16 -2
  119. package/src/components/BaseModal.vue +2 -1
  120. package/src/components/ExperimentSelectorModal.story.vue +38 -0
  121. package/src/components/ExperimentSelectorModal.vue +20 -1
  122. package/src/components/GeneratedPluginView.vue +4 -9
  123. package/src/components/GeneratedResultRenderer.vue +3 -4
  124. package/src/components/JobsStatusTray.story.vue +97 -43
  125. package/src/components/JobsStatusTray.vue +287 -290
  126. package/src/components/LayoutResizeHandle.story.vue +65 -4
  127. package/src/components/PluginWorkspaceView.props.ts +3 -0
  128. package/src/components/PluginWorkspaceView.vue +17 -0
  129. package/src/components/SampleSelector.story.vue +21 -6
  130. package/src/components/SampleSelector.vue +10 -3
  131. package/src/components/SectionCard.story.vue +33 -0
  132. package/src/components/SettingsModal.vue +7 -12
  133. package/src/components/Tooltip.vue +9 -32
  134. package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
  135. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  136. package/src/components/internal/DatePickerDateInternal.vue +7 -45
  137. package/src/components/internal/DatePickerDateTimeInternal.vue +7 -1
  138. package/src/components/internal/DatePickerTimeInternal.vue +8 -1
  139. package/src/components/internal/NumberUnitInputInternal.vue +4 -18
  140. package/src/components/internal/OnboardingLayerInternal.vue +173 -0
  141. package/src/components/internal/SelectMultipleInternal.vue +6 -1
  142. package/src/components/internal/SelectSearchableInternal.vue +6 -1
  143. package/src/components/internal/WellEditPopupInternal.vue +11 -22
  144. package/src/components/internal/WorkspaceShellInternal.vue +12 -0
  145. package/src/composables/pluginWorkspaceModel.ts +2 -2
  146. package/src/composables/useFileImport.ts +51 -1
  147. package/src/composables/useFloatingPanel.ts +107 -0
  148. package/src/composables/useJobCenter.ts +188 -6
  149. package/src/composables/useOnboarding.ts +465 -0
  150. package/src/composables/usePluginWorkspace.ts +1 -1
  151. package/src/data.ts +1 -0
  152. package/src/runtime.ts +2 -1
  153. package/src/shell.ts +17 -0
  154. package/src/stores/index.ts +0 -2
  155. package/src/stores/settings.ts +20 -50
  156. package/src/styles/components/action-menu.css +1 -1
  157. package/src/styles/components/app-layout.css +6 -3
  158. package/src/styles/components/app-page-selector.css +120 -45
  159. package/src/styles/components/app-top-bar.css +165 -3
  160. package/src/styles/components/button.css +8 -0
  161. package/src/styles/components/dataframe.css +1 -1
  162. package/src/styles/components/date-picker.css +4 -2
  163. package/src/styles/components/datetime-picker.css +4 -4
  164. package/src/styles/components/experiment-selector-modal.css +13 -0
  165. package/src/styles/components/jobs-status-tray.css +134 -296
  166. package/src/styles/components/layout-resize-handle.css +59 -16
  167. package/src/styles/components/modal.css +3 -3
  168. package/src/styles/components/number-input.css +1 -1
  169. package/src/styles/components/onboarding.css +368 -0
  170. package/src/styles/components/progress-bar.css +3 -3
  171. package/src/styles/components/sample-selector.css +43 -0
  172. package/src/styles/components/searchable-select.css +3 -7
  173. package/src/styles/components/section-card.css +30 -6
  174. package/src/styles/components/settings-modal.css +7 -2
  175. package/src/styles/components/time-picker.css +3 -6
  176. package/src/styles/components/toast.css +1 -1
  177. package/src/styles/components/tooltip.css +2 -2
  178. package/src/styles/components/unit-input.css +1 -1
  179. package/src/styles/components/well-edit-popup.css +2 -2
  180. package/src/styles/index.css +1 -0
  181. package/src/styles/variables.css +153 -15
  182. package/src/types/components.ts +2 -0
  183. package/src/types/index.ts +1 -0
  184. package/src/types/jobs.ts +10 -0
  185. package/src/types/platform.ts +1 -1
  186. package/dist/AppSidebar-Dq9W1jE2.js.map +0 -1
  187. package/dist/ExperimentSelectorModal-65peG4Up.js.map +0 -1
  188. package/dist/SettingsModal-483nyI6b.js.map +0 -1
  189. package/dist/experiment-43OJtH7R.js.map +0 -1
  190. package/dist/records-B6gpM_3e.js.map +0 -1
  191. package/dist/runtime-7vfl_bI3.js.map +0 -1
  192. package/dist/useDropdownState-8yWMu-7_.js.map +0 -1
  193. package/dist/useExperimentSamples-DHnxKFAF.js.map +0 -1
  194. package/dist/useListReorder-BitdUhxn.js.map +0 -1
  195. package/dist/useRackEditor-DiwCt77M.js.map +0 -1
  196. package/dist/useRealtime-C3iy9QkU.js +0 -699
  197. package/dist/useRealtime-C3iy9QkU.js.map +0 -1
  198. package/dist/useRequest-D506eHi8.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-7vfl_bI3.js","names":["$emit","$attrs"],"sources":["../src/composables/useToast.ts","../src/components/AppToastContainer.vue","../src/components/AppToastContainer.vue","../src/composables/controlWorkspaceOptions.ts","../src/composables/useControlWorkspace.ts","../src/components/internal/WorkspaceControlsInternal.vue","../src/components/internal/WorkspaceControlsInternal.vue","../src/components/internal/WorkspaceShellInternal.vue","../src/components/internal/WorkspaceShellInternal.vue","../src/components/internal/WorkspaceSidebarInternal.vue","../src/components/internal/WorkspaceSidebarInternal.vue","../src/components/PluginWorkspaceView.vue","../src/components/PluginWorkspaceView.vue","../src/components/Avatar.vue","../src/components/Avatar.vue","../src/generated/schema.ts","../src/components/GeneratedPluginView.vue","../src/components/GeneratedPluginView.vue","../src/components/internal/PlateEditorBindingInternal.vue","../src/components/internal/PlateEditorBindingInternal.vue","../src/components/ComponentBindingRenderer.vue","../src/components/ComponentBindingRenderer.vue","../src/components/RuntimeUpdateNotice.vue","../src/components/RuntimeUpdateNotice.vue","../src/composables/usePresence.ts","../src/utils/presenceAvatars.ts","../src/components/PresenceAvatars.vue","../src/components/PresenceAvatars.vue","../src/runtime.ts"],"sourcesContent":["import { ref } from 'vue'\nimport type { Toast, ToastOptions } from '../types'\n\nconst toasts = ref<Toast[]>([])\nlet nextId = 0\n\n/** Options of `success()`, `error()`, `warning()` and `info()`: the message is the title. */\ntype ToastMessageOptions = Omit<ToastOptions, 'title' | 'type'>\n\n/** Reactive global toast queue with success/error/warning/info variants and auto-dismiss timers. */\nexport function useToast() {\n /** Push a structured toast. `progress: 'indeterminate'` is the in-progress form and never auto-dismisses. */\n function push(options: ToastOptions): number {\n const id = nextId++\n const duration = options.duration ?? 3500\n toasts.value.push({\n id,\n type: 'success',\n ...options,\n message: options.message ?? options.title,\n duration,\n actions: options.actions?.slice(0, 2),\n })\n if (options.progress !== 'indeterminate') {\n setTimeout(() => dismiss(id), duration)\n }\n return id\n }\n\n function notify(type: Toast['type'], duration: number, message: string, options: ToastMessageOptions = {}): number {\n return push({ duration, ...options, title: message, type })\n }\n\n function success(message: string, options?: ToastMessageOptions): number {\n return notify('success', 3500, message, options)\n }\n\n function error(message: string, options?: ToastMessageOptions): number {\n return notify('error', 5000, message, options)\n }\n\n function warning(message: string, options?: ToastMessageOptions): number {\n return notify('warning', 4000, message, options)\n }\n\n function info(message: string, options?: ToastMessageOptions): number {\n return notify('info', 3500, message, options)\n }\n\n function dismiss(id: number) {\n toasts.value = toasts.value.filter(t => t.id !== id)\n }\n\n function clear() {\n toasts.value = []\n }\n\n return { toasts, push, success, error, warning, info, dismiss, clear }\n}\n","<script setup lang=\"ts\">\n/** Preferred toast container driven by useToast: title/detail, up to two actions, TTL or indeterminate bar, click-to-close. */\nimport { useToast } from '../composables/useToast'\nimport type { Toast, ToastAction } from '../types'\n\nconst { toasts, dismiss } = useToast()\n\nfunction title(toast: Toast): string {\n return toast.title ?? toast.message\n}\n\nfunction actions(toast: Toast): ToastAction[] {\n return (toast.actions ?? []).slice(0, 2)\n}\n\nfunction progress(toast: Toast): NonNullable<Toast['progress']> {\n return toast.progress ?? 'ttl'\n}\n\nfunction runAction(toast: Toast, action: ToastAction) {\n action.onClick()\n dismiss(toast.id)\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div class=\"mint-toast__container\">\n <TransitionGroup name=\"toast\">\n <div\n v-for=\"toast in toasts\"\n :key=\"toast.id\"\n :class=\"[\n 'mint-toast__item',\n `mint-toast__item--${toast.type}`,\n (toast.count ?? 1) > 1 ? 'mint-toast__item--stacked' : '',\n ]\"\n :role=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n @click=\"dismiss(toast.id)\"\n >\n <!-- Lucide circle-check -->\n <svg v-if=\"toast.type === 'success'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n <!-- Lucide circle-x -->\n <svg v-else-if=\"toast.type === 'error'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m15 9-6 6\" /><path d=\"m9 9 6 6\" />\n </svg>\n <!-- Lucide triangle-alert -->\n <svg v-else-if=\"toast.type === 'warning'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" /><path d=\"M12 9v4\" /><path d=\"M12 17h.01\" />\n </svg>\n <!-- Lucide info -->\n <svg v-else class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 16v-4\" /><path d=\"M12 8h.01\" />\n </svg>\n\n <div class=\"mint-toast__body\">\n <div class=\"mint-toast__title\">\n <span class=\"mint-toast__message\">{{ title(toast) }}</span>\n <span v-if=\"(toast.count ?? 1) > 1\" class=\"mint-toast__count\">×{{ toast.count }}</span>\n </div>\n <div v-if=\"toast.detail\" class=\"mint-toast__detail\">{{ toast.detail }}</div>\n <div v-if=\"actions(toast).length\" class=\"mint-toast__actions\">\n <button\n v-for=\"action in actions(toast)\"\n :key=\"action.label\"\n type=\"button\"\n :class=\"['mint-toast__action', action.primary ? 'mint-toast__action--primary' : '']\"\n @click.stop=\"runAction(toast, action)\"\n >\n {{ action.label }}\n </button>\n </div>\n </div>\n\n <button\n v-if=\"toast.dismissible !== false\"\n type=\"button\"\n class=\"mint-toast__close\"\n aria-label=\"Dismiss\"\n @click.stop=\"dismiss(toast.id)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n <span\n v-if=\"progress(toast) === 'ttl'\"\n class=\"mint-toast__progress\"\n :style=\"{ animationDuration: `${toast.duration ?? 3500}ms` }\"\n />\n <span\n v-else-if=\"progress(toast) === 'indeterminate'\"\n class=\"mint-toast__progress mint-toast__progress--indeterminate\"\n />\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\n/** Preferred toast container driven by useToast: title/detail, up to two actions, TTL or indeterminate bar, click-to-close. */\nimport { useToast } from '../composables/useToast'\nimport type { Toast, ToastAction } from '../types'\n\nconst { toasts, dismiss } = useToast()\n\nfunction title(toast: Toast): string {\n return toast.title ?? toast.message\n}\n\nfunction actions(toast: Toast): ToastAction[] {\n return (toast.actions ?? []).slice(0, 2)\n}\n\nfunction progress(toast: Toast): NonNullable<Toast['progress']> {\n return toast.progress ?? 'ttl'\n}\n\nfunction runAction(toast: Toast, action: ToastAction) {\n action.onClick()\n dismiss(toast.id)\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div class=\"mint-toast__container\">\n <TransitionGroup name=\"toast\">\n <div\n v-for=\"toast in toasts\"\n :key=\"toast.id\"\n :class=\"[\n 'mint-toast__item',\n `mint-toast__item--${toast.type}`,\n (toast.count ?? 1) > 1 ? 'mint-toast__item--stacked' : '',\n ]\"\n :role=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n @click=\"dismiss(toast.id)\"\n >\n <!-- Lucide circle-check -->\n <svg v-if=\"toast.type === 'success'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n <!-- Lucide circle-x -->\n <svg v-else-if=\"toast.type === 'error'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m15 9-6 6\" /><path d=\"m9 9 6 6\" />\n </svg>\n <!-- Lucide triangle-alert -->\n <svg v-else-if=\"toast.type === 'warning'\" class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" /><path d=\"M12 9v4\" /><path d=\"M12 17h.01\" />\n </svg>\n <!-- Lucide info -->\n <svg v-else class=\"mint-toast__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 16v-4\" /><path d=\"M12 8h.01\" />\n </svg>\n\n <div class=\"mint-toast__body\">\n <div class=\"mint-toast__title\">\n <span class=\"mint-toast__message\">{{ title(toast) }}</span>\n <span v-if=\"(toast.count ?? 1) > 1\" class=\"mint-toast__count\">×{{ toast.count }}</span>\n </div>\n <div v-if=\"toast.detail\" class=\"mint-toast__detail\">{{ toast.detail }}</div>\n <div v-if=\"actions(toast).length\" class=\"mint-toast__actions\">\n <button\n v-for=\"action in actions(toast)\"\n :key=\"action.label\"\n type=\"button\"\n :class=\"['mint-toast__action', action.primary ? 'mint-toast__action--primary' : '']\"\n @click.stop=\"runAction(toast, action)\"\n >\n {{ action.label }}\n </button>\n </div>\n </div>\n\n <button\n v-if=\"toast.dismissible !== false\"\n type=\"button\"\n class=\"mint-toast__close\"\n aria-label=\"Dismiss\"\n @click.stop=\"dismiss(toast.id)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n <span\n v-if=\"progress(toast) === 'ttl'\"\n class=\"mint-toast__progress\"\n :style=\"{ animationDuration: `${toast.duration ?? 3500}ms` }\"\n />\n <span\n v-else-if=\"progress(toast) === 'indeterminate'\"\n class=\"mint-toast__progress mint-toast__progress--indeterminate\"\n />\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n</template>\n","import type {\n ControlWorkspaceOptions,\n} from './controlSchemaTypes'\n\nexport function mergeControlWorkspaceOptions(\n base?: ControlWorkspaceOptions,\n override?: ControlWorkspaceOptions,\n): ControlWorkspaceOptions {\n return {\n ...(base ?? {}),\n ...(override ?? {}),\n initialValues: {\n ...(base?.initialValues ?? {}),\n ...(override?.initialValues ?? {}),\n },\n topBarSettings: {\n ...(base?.topBarSettings ?? {}),\n ...(override?.topBarSettings ?? {}),\n },\n }\n}\n","import {\n computed,\n reactive,\n ref,\n watch,\n} from 'vue'\nimport type {\n PillNavItem,\n TopBarSettingsConfig,\n} from '../types'\nimport {\n replaceRecord,\n} from './controlSchemaUtils'\nimport {\n mergeControlWorkspaceOptions,\n} from './controlWorkspaceOptions'\nimport {\n controlValuesToComponentBindings,\n controlValuesToComponentBindingsById,\n controlValuesToComponentProps,\n} from './controlComponentBindings'\nimport {\n isControlModelBinding,\n} from './controlSchemaModel'\nimport {\n useControlSchema,\n} from './useControlSchema'\nimport type {\n ControlComponentBinding,\n ControlComponentBindingsById,\n ControlComponentBindingsConfig,\n ControlComponentPropsByIdMap,\n ControlComponentPropsMap,\n ControlModelBinding,\n ControlSchema,\n ControlValues,\n ControlWorkspaceComponentBindings,\n ControlWorkspaceFormBinding,\n ControlWorkspaceOptions,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlWorkspaceReturn,\n} from './controlSchemaTypes'\n\n/**\n * Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model.\n *\n * @example Recommended\n * ```ts\n * const workspace = useControlWorkspace(workspaceModel)\n * const { form, sidebar, topBar } = workspace.bindings\n * ```\n */\nexport function useControlWorkspace<TControls extends ControlSchema>(\n controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),\n options: ControlWorkspaceOptions = {},\n): UseControlWorkspaceReturn<TControls> {\n const model = isControlModelBinding<ControlModelBinding & { controls: TControls }>(controlsOrModel)\n ? controlsOrModel\n : undefined\n const controls: TControls = model ? model.controls : controlsOrModel as TControls\n const workspaceOptions = model\n ? mergeControlWorkspaceOptions(model.controlOptions, options)\n : options\n const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions\n const schema = useControlSchema(controls, schemaOptions)\n const activeView = ref(schema.defaultView)\n const values = reactive({\n ...schema.initialValues,\n ...(initialValues ?? {}),\n }) as ControlValues<TControls> & Record<string, unknown>\n\n function setActiveView(viewId: string) {\n syncActiveView(viewId)\n }\n\n function syncActiveView(viewId: string) {\n if (!schema.viewIds.includes(viewId)) return\n if (activeView.value !== viewId) activeView.value = viewId\n if (sidebar.activeView !== viewId) sidebar.activeView = viewId\n if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId\n }\n\n function setValues(nextValues: Record<string, unknown>) {\n Object.assign(values, nextValues)\n }\n\n function resetValues(nextValues: Record<string, unknown> = {}) {\n replaceRecord(values, {\n ...schema.initialValues,\n ...nextValues,\n })\n }\n\n function getComponentProps(\n mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, unknown> {\n return controlValuesToComponentProps(values, mapping)\n }\n\n function getComponentPropsById(\n mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, Record<string, unknown>> {\n if (mappings === undefined) return {}\n\n return Object.fromEntries(\n Object.entries(mappings).map(([id, mapping]) => [\n id,\n controlValuesToComponentProps(values, mapping),\n ]),\n )\n }\n\n function getComponentBindings(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBinding[] {\n return controlValuesToComponentBindings(values, bindings)\n }\n\n function getComponentBindingsById(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBindingsById {\n return controlValuesToComponentBindingsById(values, bindings)\n }\n\n const componentProps = computed(() => (\n model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)\n ))\n const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))\n const componentBindings = computed(() => getComponentBindings(model?.componentBindings))\n const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))\n const form = {\n ...schema.form,\n modelValue: values,\n 'onUpdate:modelValue': setValues,\n } as ControlWorkspaceFormBinding\n\n const topBarSettingsConfig: TopBarSettingsConfig = {\n ...schema.topBarSettingsConfig,\n ...(topBarSettings ?? {}),\n values,\n }\n const sidebar = reactive({\n ...schema.sidebar,\n activeView: activeView.value,\n values,\n 'onUpdate:values': setValues,\n }) as ControlWorkspaceSidebarBinding\n const pillNav = reactive({\n items: schema.viewItems,\n currentItemId: activeView.value,\n onSelect: (item: PillNavItem) => setActiveView(item.id),\n }) as ControlWorkspacePillNavBinding\n const topBarSettingsBinding = {\n spec: { settings: topBarSettingsConfig },\n onSettingsValuesChange: setValues,\n } as ControlWorkspaceTopBarSettingsBinding\n const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({\n spec: { pills: pillNav.items, settings: topBarSettingsConfig },\n pill: pillNav.currentItemId,\n onPillSelect: pillNav.onSelect,\n onSettingsValuesChange: setValues,\n }))\n const bindings: ControlWorkspaceComponentBindings = {\n form,\n sidebar,\n topBar: topBarProps,\n topBarSettings: topBarSettingsBinding,\n pillNav,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n }\n\n watch(activeView, syncActiveView, { flush: 'sync' })\n watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })\n watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })\n\n return {\n ...schema,\n schema,\n values,\n activeView,\n topBarSettingsConfig,\n form,\n sidebar,\n topBar: topBarProps,\n pillNav,\n topBarSettings: topBarSettingsBinding,\n bindings,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n setActiveView,\n setValues,\n resetValues,\n getComponentProps,\n getComponentPropsById,\n getComponentBindings,\n getComponentBindingsById,\n }\n}\n","<script setup lang=\"ts\">\n/**\n * Internal: renders PluginWorkspaceView's default (main content) slot bound to the\n * control-schema-derived scoped-slot payload (active view, values, component bindings/props).\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type { PluginWorkspaceControlsModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n controls: PluginWorkspaceControlsModel\n}>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceControlsModel) => unknown\n}>()\n</script>\n\n<template>\n <slot v-bind=\"controls\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: renders PluginWorkspaceView's default (main content) slot bound to the\n * control-schema-derived scoped-slot payload (active view, values, component bindings/props).\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type { PluginWorkspaceControlsModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n controls: PluginWorkspaceControlsModel\n}>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceControlsModel) => unknown\n}>()\n</script>\n\n<template>\n <slot v-bind=\"controls\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppLayout + AppTopBar for PluginWorkspaceView, driven by a single `shell` model.\n * Owns the responsive/collapse layout props and the top bar's default rendering; the caller\n * decides whether to override the `topbar`/`sidebar` slots and supplies the sidebar content.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../../types'\nimport AppLayout from '../AppLayout.vue'\nimport AppTopBar from '../AppTopBar.vue'\nimport type { PluginWorkspaceShellModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\n}>()\n\nconst emit = defineEmits<{\n 'pill-select': [item: PillNavItem]\n 'pill-option-select': [option: PillNavOption, item: PillNavItem]\n 'settings-values-change': [data: Record<string, unknown>]\n}>()\n\nfunction handlePillOptionSelect(option: PillNavOption, item: PillNavItem) {\n emit('pill-option-select', option, item)\n}\n\ndefineSlots<{\n topbar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n sidebar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n default?: (props: PluginWorkspaceShellModel['controls']) => unknown\n icon?: (props: Record<string, unknown>) => unknown\n logo?: (props: Record<string, unknown>) => unknown\n nav?: (props: Record<string, unknown>) => unknown\n center?: (props: Record<string, unknown>) => unknown\n actions?: (props: Record<string, unknown>) => unknown\n 'settings-appearance'?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppLayout\n class=\"mint-plugin-workspace-view\"\n :sidebar-position=\"shell.sidebarPosition\"\n :sidebar-width=\"shell.sidebarWidth\"\n :floating=\"shell.floating\"\n :responsive-sidebar=\"shell.responsiveSidebar\"\n :sidebar-toggle-label=\"shell.sidebarToggleLabel\"\n :sidebar-close-label=\"shell.sidebarCloseLabel\"\n >\n <template #topbar>\n <slot name=\"topbar\" v-bind=\"shell.controls\">\n <AppTopBar\n v-if=\"shell.topBar\"\n :title=\"shell.title\"\n :subtitle=\"shell.subtitle\"\n :spec=\"shell.topBar\"\n :pill=\"shell.pill\"\n @pill-select=\"emit('pill-select', $event)\"\n @pill-option-select=\"handlePillOptionSelect\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppTopBar>\n </slot>\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar>\n <slot name=\"sidebar\" v-bind=\"shell.controls\" />\n </template>\n\n <slot v-bind=\"shell.controls\" />\n </AppLayout>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppLayout + AppTopBar for PluginWorkspaceView, driven by a single `shell` model.\n * Owns the responsive/collapse layout props and the top bar's default rendering; the caller\n * decides whether to override the `topbar`/`sidebar` slots and supplies the sidebar content.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../../types'\nimport AppLayout from '../AppLayout.vue'\nimport AppTopBar from '../AppTopBar.vue'\nimport type { PluginWorkspaceShellModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\n}>()\n\nconst emit = defineEmits<{\n 'pill-select': [item: PillNavItem]\n 'pill-option-select': [option: PillNavOption, item: PillNavItem]\n 'settings-values-change': [data: Record<string, unknown>]\n}>()\n\nfunction handlePillOptionSelect(option: PillNavOption, item: PillNavItem) {\n emit('pill-option-select', option, item)\n}\n\ndefineSlots<{\n topbar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n sidebar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n default?: (props: PluginWorkspaceShellModel['controls']) => unknown\n icon?: (props: Record<string, unknown>) => unknown\n logo?: (props: Record<string, unknown>) => unknown\n nav?: (props: Record<string, unknown>) => unknown\n center?: (props: Record<string, unknown>) => unknown\n actions?: (props: Record<string, unknown>) => unknown\n 'settings-appearance'?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppLayout\n class=\"mint-plugin-workspace-view\"\n :sidebar-position=\"shell.sidebarPosition\"\n :sidebar-width=\"shell.sidebarWidth\"\n :floating=\"shell.floating\"\n :responsive-sidebar=\"shell.responsiveSidebar\"\n :sidebar-toggle-label=\"shell.sidebarToggleLabel\"\n :sidebar-close-label=\"shell.sidebarCloseLabel\"\n >\n <template #topbar>\n <slot name=\"topbar\" v-bind=\"shell.controls\">\n <AppTopBar\n v-if=\"shell.topBar\"\n :title=\"shell.title\"\n :subtitle=\"shell.subtitle\"\n :spec=\"shell.topBar\"\n :pill=\"shell.pill\"\n @pill-select=\"emit('pill-select', $event)\"\n @pill-option-select=\"handlePillOptionSelect\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppTopBar>\n </slot>\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar>\n <slot name=\"sidebar\" v-bind=\"shell.controls\" />\n </template>\n\n <slot v-bind=\"shell.controls\" />\n </AppLayout>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppSidebar for PluginWorkspaceView, driven by a single `sidebar` model covering\n * chrome, panels/forms, collapse behavior, and the compact control-schema props that drive\n * AppSidebar's auto-generated form.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport AppSidebar from '../AppSidebar.vue'\nimport type { PluginWorkspaceSidebarModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n sidebar: PluginWorkspaceSidebarModel\n}>()\n\ndefineEmits<{\n 'update:values': [values: Record<string, unknown>]\n 'update:collapsed': [value: boolean]\n 'update:toggle': [sectionId: string, value: boolean]\n 'section-action': [sectionId: string, actionId: string]\n 'form-submit': [sectionId: string, values: Record<string, unknown>]\n 'form-cancel': [sectionId: string]\n}>()\n\ndefineSlots<{\n header?: (props: Record<string, unknown>) => unknown\n collapsed?: (props: Record<string, unknown>) => unknown\n 'collapsed-footer'?: (props: Record<string, unknown>) => unknown\n footer?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppSidebar\n :spec=\"sidebar.spec\"\n :active-view=\"sidebar.activeView\"\n :values=\"sidebar.values\"\n :collapsed=\"sidebar.collapsed\"\n :form-loading=\"sidebar.formLoading\"\n :form-disabled=\"sidebar.formDisabled\"\n :form-readonly=\"sidebar.formReadonly\"\n @update:values=\"$emit('update:values', $event)\"\n @update:collapsed=\"$emit('update:collapsed', $event)\"\n @update:toggle=\"(sectionId, value) => $emit('update:toggle', sectionId, value)\"\n @section-action=\"(sectionId, actionId) => $emit('section-action', sectionId, actionId)\"\n @form-submit=\"(sectionId, values) => $emit('form-submit', sectionId, values)\"\n @form-cancel=\"$emit('form-cancel', $event)\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppSidebar>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppSidebar for PluginWorkspaceView, driven by a single `sidebar` model covering\n * chrome, panels/forms, collapse behavior, and the compact control-schema props that drive\n * AppSidebar's auto-generated form.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport AppSidebar from '../AppSidebar.vue'\nimport type { PluginWorkspaceSidebarModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n sidebar: PluginWorkspaceSidebarModel\n}>()\n\ndefineEmits<{\n 'update:values': [values: Record<string, unknown>]\n 'update:collapsed': [value: boolean]\n 'update:toggle': [sectionId: string, value: boolean]\n 'section-action': [sectionId: string, actionId: string]\n 'form-submit': [sectionId: string, values: Record<string, unknown>]\n 'form-cancel': [sectionId: string]\n}>()\n\ndefineSlots<{\n header?: (props: Record<string, unknown>) => unknown\n collapsed?: (props: Record<string, unknown>) => unknown\n 'collapsed-footer'?: (props: Record<string, unknown>) => unknown\n footer?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppSidebar\n :spec=\"sidebar.spec\"\n :active-view=\"sidebar.activeView\"\n :values=\"sidebar.values\"\n :collapsed=\"sidebar.collapsed\"\n :form-loading=\"sidebar.formLoading\"\n :form-disabled=\"sidebar.formDisabled\"\n :form-readonly=\"sidebar.formReadonly\"\n @update:values=\"$emit('update:values', $event)\"\n @update:collapsed=\"$emit('update:collapsed', $event)\"\n @update:toggle=\"(sectionId, value) => $emit('update:toggle', sectionId, value)\"\n @section-action=\"(sectionId, actionId) => $emit('section-action', sectionId, actionId)\"\n @form-submit=\"(sectionId, values) => $emit('form-submit', sectionId, values)\"\n @form-cancel=\"$emit('form-cancel', $event)\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppSidebar>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Standard plugin workspace shell that combines AppLayout, AppTopBar, and AppSidebar with LEAF-style defaults.\n *\n * The structure is one `:spec` built with `definePluginWorkspaceView()`: title,\n * top bar, sidebar (a `defineControlModel()` result generates its sections),\n * the experiment chip and its save action. The active pill, view, sidebar\n * values and collapse state are `v-model`s. It renders the toast container\n * unless `spec.toasts` is false.\n *\n * @example Recommended\n * ```vue\n * <PluginWorkspaceView :spec=\"workspace\" v-model:pill=\"tab\">\n * <router-view />\n * </PluginWorkspaceView>\n * ```\n */\nimport { computed, toValue, useSlots } from 'vue'\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../types'\nimport { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.vue'\nimport WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'\nimport WorkspaceShellInternal from './internal/WorkspaceShellInternal.vue'\nimport WorkspaceSidebarInternal from './internal/WorkspaceSidebarInternal.vue'\nimport type {\n PluginWorkspaceForwardedSlotProps,\n PluginWorkspaceSlotProps,\n PluginWorkspaceViewEmits,\n PluginWorkspaceViewProps,\n} from './PluginWorkspaceView.props'\n\nconst props = withDefaults(defineProps<PluginWorkspaceViewProps>(), {\n spec: () => ({}),\n pill: undefined,\n view: undefined,\n values: undefined,\n sidebarCollapsed: undefined,\n formLoading: false,\n formDisabled: false,\n formReadonly: false,\n})\n\nconst emit = defineEmits<PluginWorkspaceViewEmits>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceSlotProps) => unknown\n topbar?: (props: PluginWorkspaceSlotProps) => unknown\n sidebar?: (props: PluginWorkspaceSlotProps) => unknown\n icon?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n logo?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n nav?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n center?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n actions?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'settings-appearance'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n header?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n collapsed?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'collapsed-footer'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n footer?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n}>()\n\nconst slots = useSlots()\n\n// The experiment chip is setup-time structure, like the rest of the spec.\nif (props.spec.experiment) {\n const save = props.spec.save\n useAppExperiment({\n onSelect: experiment => emit('experiment-select', experiment),\n onSave: save ? async () => (await save.handler()) ?? null : undefined,\n onDetach: () => emit('experiment-detach'),\n saveDisabled: computed(() => toValue(save?.disabled) ?? false),\n saveDisabledMessage: computed(() => toValue(save?.reason)),\n })\n}\n\nconst {\n shell,\n sidebar,\n controls,\n handleControlValuesUpdate,\n handlePillSelect,\n} = usePluginWorkspace({\n props,\n slots,\n emit,\n})\n\nfunction handleToggle(sectionId: string, value: boolean) {\n emit('update:toggle', sectionId, value)\n}\n\nfunction handleFormSubmit(sectionId: string, values: Record<string, unknown>) {\n emit('form-submit', sectionId, values)\n}\n\nfunction handleFormCancel(sectionId: string) {\n emit('form-cancel', sectionId)\n}\n\n</script>\n\n<template>\n <WorkspaceShellInternal\n :shell=\"shell\"\n @pill-select=\"handlePillSelect\"\n @pill-option-select=\"(option: PillNavOption, item: PillNavItem) => emit('pill-option-select', option, item)\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template v-if=\"slots.topbar\" #topbar=\"scope\">\n <slot name=\"topbar\" v-bind=\"scope\" />\n </template>\n\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar=\"scope\">\n <slot name=\"sidebar\" v-bind=\"scope\">\n <WorkspaceSidebarInternal\n :sidebar=\"sidebar\"\n @update:values=\"handleControlValuesUpdate\"\n @update:collapsed=\"emit('update:sidebarCollapsed', $event)\"\n @update:toggle=\"handleToggle\"\n @section-action=\"(sectionId: string, actionId: string) => emit('section-action', sectionId, actionId)\"\n @form-submit=\"handleFormSubmit\"\n @form-cancel=\"handleFormCancel\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </WorkspaceSidebarInternal>\n </slot>\n </template>\n\n <template #default>\n <WorkspaceControlsInternal :controls=\"controls\">\n <template #default=\"controlsScope\">\n <slot v-bind=\"controlsScope\" />\n </template>\n </WorkspaceControlsInternal>\n <AppToastContainer v-if=\"spec.toasts !== false\" />\n </template>\n </WorkspaceShellInternal>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Standard plugin workspace shell that combines AppLayout, AppTopBar, and AppSidebar with LEAF-style defaults.\n *\n * The structure is one `:spec` built with `definePluginWorkspaceView()`: title,\n * top bar, sidebar (a `defineControlModel()` result generates its sections),\n * the experiment chip and its save action. The active pill, view, sidebar\n * values and collapse state are `v-model`s. It renders the toast container\n * unless `spec.toasts` is false.\n *\n * @example Recommended\n * ```vue\n * <PluginWorkspaceView :spec=\"workspace\" v-model:pill=\"tab\">\n * <router-view />\n * </PluginWorkspaceView>\n * ```\n */\nimport { computed, toValue, useSlots } from 'vue'\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../types'\nimport { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.vue'\nimport WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'\nimport WorkspaceShellInternal from './internal/WorkspaceShellInternal.vue'\nimport WorkspaceSidebarInternal from './internal/WorkspaceSidebarInternal.vue'\nimport type {\n PluginWorkspaceForwardedSlotProps,\n PluginWorkspaceSlotProps,\n PluginWorkspaceViewEmits,\n PluginWorkspaceViewProps,\n} from './PluginWorkspaceView.props'\n\nconst props = withDefaults(defineProps<PluginWorkspaceViewProps>(), {\n spec: () => ({}),\n pill: undefined,\n view: undefined,\n values: undefined,\n sidebarCollapsed: undefined,\n formLoading: false,\n formDisabled: false,\n formReadonly: false,\n})\n\nconst emit = defineEmits<PluginWorkspaceViewEmits>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceSlotProps) => unknown\n topbar?: (props: PluginWorkspaceSlotProps) => unknown\n sidebar?: (props: PluginWorkspaceSlotProps) => unknown\n icon?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n logo?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n nav?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n center?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n actions?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'settings-appearance'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n header?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n collapsed?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'collapsed-footer'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n footer?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n}>()\n\nconst slots = useSlots()\n\n// The experiment chip is setup-time structure, like the rest of the spec.\nif (props.spec.experiment) {\n const save = props.spec.save\n useAppExperiment({\n onSelect: experiment => emit('experiment-select', experiment),\n onSave: save ? async () => (await save.handler()) ?? null : undefined,\n onDetach: () => emit('experiment-detach'),\n saveDisabled: computed(() => toValue(save?.disabled) ?? false),\n saveDisabledMessage: computed(() => toValue(save?.reason)),\n })\n}\n\nconst {\n shell,\n sidebar,\n controls,\n handleControlValuesUpdate,\n handlePillSelect,\n} = usePluginWorkspace({\n props,\n slots,\n emit,\n})\n\nfunction handleToggle(sectionId: string, value: boolean) {\n emit('update:toggle', sectionId, value)\n}\n\nfunction handleFormSubmit(sectionId: string, values: Record<string, unknown>) {\n emit('form-submit', sectionId, values)\n}\n\nfunction handleFormCancel(sectionId: string) {\n emit('form-cancel', sectionId)\n}\n\n</script>\n\n<template>\n <WorkspaceShellInternal\n :shell=\"shell\"\n @pill-select=\"handlePillSelect\"\n @pill-option-select=\"(option: PillNavOption, item: PillNavItem) => emit('pill-option-select', option, item)\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template v-if=\"slots.topbar\" #topbar=\"scope\">\n <slot name=\"topbar\" v-bind=\"scope\" />\n </template>\n\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar=\"scope\">\n <slot name=\"sidebar\" v-bind=\"scope\">\n <WorkspaceSidebarInternal\n :sidebar=\"sidebar\"\n @update:values=\"handleControlValuesUpdate\"\n @update:collapsed=\"emit('update:sidebarCollapsed', $event)\"\n @update:toggle=\"handleToggle\"\n @section-action=\"(sectionId: string, actionId: string) => emit('section-action', sectionId, actionId)\"\n @form-submit=\"handleFormSubmit\"\n @form-cancel=\"handleFormCancel\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </WorkspaceSidebarInternal>\n </slot>\n </template>\n\n <template #default>\n <WorkspaceControlsInternal :controls=\"controls\">\n <template #default=\"controlsScope\">\n <slot v-bind=\"controlsScope\" />\n </template>\n </WorkspaceControlsInternal>\n <AppToastContainer v-if=\"spec.toasts !== false\" />\n </template>\n </WorkspaceShellInternal>\n</template>\n","<script setup lang=\"ts\">\n/** Displays a user avatar as an image, a single derived initial, or a fallback icon, on a quiet accent face (or an explicit `color`) with an optional status dot. */\nimport { computed } from 'vue'\n\ninterface Props {\n name?: string\n initials?: string\n src?: string\n alt?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n color?: string\n status?: 'online' | 'away' | 'busy' | 'offline'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n size: 'md',\n})\n\n// Default: first letter of `name`, uppercased. Consumers wanting two letters\n// (e.g. role badges like \"PI\", \"QC\") pass `:initials=\"'XX'\"` explicitly.\nconst computedInitials = computed(() =>\n props.initials || props.name?.charAt(0).toUpperCase() || ''\n)\n\n// The quiet accent face lives in avatar.css; an explicit `color` fills the\n// face. That fill is a fixed hue (role badges), so the ink stays white in both\n// themes instead of following the theme-dependent --text-on-accent.\nconst faceStyle = computed(() =>\n props.color\n ? { backgroundColor: props.color, color: '#fff', boxShadow: 'none' }\n : undefined\n)\n</script>\n\n<template>\n <span\n :class=\"['mint-avatar', `mint-avatar--${size}`]\"\n role=\"img\"\n :aria-label=\"alt || name || 'User avatar'\"\n >\n <span\n class=\"mint-avatar__face\"\n :style=\"faceStyle\"\n >\n <img\n v-if=\"src\"\n :src=\"src\"\n :alt=\"alt || name || ''\"\n class=\"mint-avatar__image\"\n >\n <span v-else-if=\"computedInitials\" class=\"mint-avatar__initials\">\n {{ computedInitials }}\n </span>\n <svg\n v-else\n class=\"mint-avatar__fallback\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n </span>\n <span\n v-if=\"status\"\n :class=\"['mint-avatar__status', `mint-avatar__status--${status}`]\"\n aria-hidden=\"true\"\n />\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** Displays a user avatar as an image, a single derived initial, or a fallback icon, on a quiet accent face (or an explicit `color`) with an optional status dot. */\nimport { computed } from 'vue'\n\ninterface Props {\n name?: string\n initials?: string\n src?: string\n alt?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n color?: string\n status?: 'online' | 'away' | 'busy' | 'offline'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n size: 'md',\n})\n\n// Default: first letter of `name`, uppercased. Consumers wanting two letters\n// (e.g. role badges like \"PI\", \"QC\") pass `:initials=\"'XX'\"` explicitly.\nconst computedInitials = computed(() =>\n props.initials || props.name?.charAt(0).toUpperCase() || ''\n)\n\n// The quiet accent face lives in avatar.css; an explicit `color` fills the\n// face. That fill is a fixed hue (role badges), so the ink stays white in both\n// themes instead of following the theme-dependent --text-on-accent.\nconst faceStyle = computed(() =>\n props.color\n ? { backgroundColor: props.color, color: '#fff', boxShadow: 'none' }\n : undefined\n)\n</script>\n\n<template>\n <span\n :class=\"['mint-avatar', `mint-avatar--${size}`]\"\n role=\"img\"\n :aria-label=\"alt || name || 'User avatar'\"\n >\n <span\n class=\"mint-avatar__face\"\n :style=\"faceStyle\"\n >\n <img\n v-if=\"src\"\n :src=\"src\"\n :alt=\"alt || name || ''\"\n class=\"mint-avatar__image\"\n >\n <span v-else-if=\"computedInitials\" class=\"mint-avatar__initials\">\n {{ computedInitials }}\n </span>\n <svg\n v-else\n class=\"mint-avatar__fallback\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n </span>\n <span\n v-if=\"status\"\n :class=\"['mint-avatar__status', `mint-avatar__status--${status}`]\"\n aria-hidden=\"true\"\n />\n </span>\n</template>\n","import type {\n FormFieldSchema,\n FormFieldType,\n FormSchema,\n} from '../types/form-builder'\nimport type {\n GeneratedJsonSchema,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\n\ntype GeneratedReference = 'path'\n\ninterface ResolvedGeneratedField {\n schema: GeneratedJsonSchema\n reference?: GeneratedReference\n hasDefault: boolean\n defaultValue?: unknown\n}\n\nexport function generatedJobFormSchema(definition: GeneratedJobDefinition): FormSchema & { sections: NonNullable<FormSchema['sections']> } {\n const root = definition.input_schema\n const required = new Set(root.required ?? [])\n const fields = Object.entries(root.properties ?? {}).map(([name, schema]) =>\n toFormField(name, resolveGeneratedField(root, schema), required.has(name)),\n )\n return {\n sections: [{\n id: definition.id,\n title: definition.title,\n description: definition.description || undefined,\n columns: 1,\n fields,\n }],\n actions: true,\n submitLabel: 'Run analysis',\n }\n}\n\nexport function generatedJobDefaults(definition: GeneratedJobDefinition): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(definition.input_schema.properties ?? {})\n .map(([name, schema]) => [name, resolveGeneratedField(definition.input_schema, schema)] as const)\n .filter(([, field]) => field.hasDefault)\n .map(([name, field]) => [name, structuredClone(field.defaultValue)]),\n )\n}\n\nexport function normalizeGeneratedJobInput(\n definition: GeneratedJobDefinition,\n values: Record<string, unknown>,\n): Record<string, unknown> {\n const normalized: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(values)) {\n const field = definition.input_schema.properties?.[name]\n if (!field) continue\n const { schema, reference } = resolveGeneratedField(definition.input_schema, field)\n if (reference !== 'path' && Array.isArray(value) && ['integer', 'number'].includes(String(schema.items?.type))) {\n normalized[name] = value.map(item => {\n const numeric = typeof item === 'string' && item.trim() !== '' ? Number(item) : item\n return typeof numeric === 'number' && Number.isFinite(numeric) ? numeric : item\n })\n } else if (reference !== 'path' && Array.isArray(value) && schema.items?.type === 'boolean') {\n normalized[name] = value.map(item => item === 'true' ? true : item === 'false' ? false : item)\n } else {\n normalized[name] = value === undefined && allowsNull(schema) ? null : value\n }\n }\n return normalized\n}\n\nfunction toFormField(\n name: string,\n resolved: ResolvedGeneratedField,\n required: boolean,\n): FormFieldSchema {\n const { schema, reference } = resolved\n const validation: NonNullable<FormFieldSchema['validation']> = {}\n const allowsEmpty = schema.type === 'array' || (\n schema.type === 'string' && reference !== 'path'\n && !(schema.minLength && schema.minLength > 0)\n && (!schema.enum || schema.enum.includes(''))\n )\n if (required && !allowsNull(schema) && !allowsEmpty) validation.required = true\n if (schema.minimum !== undefined) validation.min = schema.minimum\n if (schema.maximum !== undefined) validation.max = schema.maximum\n if (schema.minLength !== undefined) validation.minLength = schema.minLength\n if (schema.maxLength !== undefined) validation.maxLength = schema.maxLength\n\n const props: Record<string, unknown> = {}\n if (schema.enum) props.options = [...schema.enum]\n if (schema.type === 'integer') {\n if (schema.exclusiveMinimum !== undefined) validation.min = Math.max(Number(validation.min ?? -Infinity), Math.floor(schema.exclusiveMinimum) + 1)\n if (schema.exclusiveMaximum !== undefined) validation.max = Math.min(Number(validation.max ?? Infinity), Math.ceil(schema.exclusiveMaximum) - 1)\n if (validation.min !== undefined) validation.min = Math.ceil(Number(validation.min))\n if (validation.max !== undefined) validation.max = Math.floor(Number(validation.max))\n if (schema.multipleOf && Number.isInteger(schema.multipleOf)) {\n if (validation.min !== undefined) validation.min = Math.ceil(Number(validation.min) / schema.multipleOf) * schema.multipleOf\n if (validation.max !== undefined) validation.max = Math.floor(Number(validation.max) / schema.multipleOf) * schema.multipleOf\n }\n props.step = 1\n }\n if (schema.type === 'integer' || schema.type === 'number') {\n if (validation.min !== undefined) props.min = validation.min\n if (validation.max !== undefined) props.max = validation.max\n if (schema.multipleOf !== undefined) props.step = schema.multipleOf\n }\n if (schema.type === 'array' && reference !== 'path') {\n if (schema.items?.enum) props.options = [...schema.items.enum]\n else props.allowDuplicates = true\n }\n if (reference === 'path' && schema.type === 'array') props.multiple = true\n return {\n name,\n label: schema.title || humanize(name),\n type: fieldType(schema, reference),\n defaultValue: resolved.hasDefault ? structuredClone(resolved.defaultValue) : undefined,\n disabled: Object.prototype.hasOwnProperty.call(schema, 'const') || undefined,\n hint: schema.description,\n validation,\n props,\n itemType: schema.items?.type === 'number' || schema.items?.type === 'integer' ? 'number' : undefined,\n }\n}\n\nfunction resolveGeneratedField(\n root: GeneratedJsonSchema,\n field: GeneratedJsonSchema,\n): ResolvedGeneratedField {\n const candidate = field.anyOf?.find(item => item.type !== 'null')\n ?? field.allOf?.[0]\n ?? field\n let schema = { ...candidate, ...field }\n if (candidate.$ref) {\n const referenceParts = candidate.$ref.split('/')\n const key = referenceParts[referenceParts.length - 1]\n const referenced = key ? root.$defs?.[key] : undefined\n if (!referenced) throw new Error(`Generated field reference is missing: ${candidate.$ref}`)\n schema = { ...referenced, ...candidate, ...field }\n }\n if (schema.items) schema.items = resolveGeneratedField(root, schema.items).schema\n const constant = Object.prototype.hasOwnProperty.call(schema, 'const')\n return {\n schema,\n reference: schema['x-mint-component'],\n hasDefault: constant || hasOwnDefault(field) || allowsNull(schema),\n defaultValue: constant ? schema.const : hasOwnDefault(field) ? field.default : null,\n }\n}\n\nfunction fieldType(schema: GeneratedJsonSchema, reference?: GeneratedReference): FormFieldType {\n if (reference === 'path') return 'path'\n if (schema.enum) return 'select'\n const type = Array.isArray(schema.type) ? schema.type.find(value => value !== 'null') : schema.type\n if (type === 'boolean') return 'toggle'\n if (type === 'number' || type === 'integer') return 'number'\n if (type === 'array') return schema.items?.enum ? 'multiselect' : 'tags'\n return 'text'\n}\n\nfunction hasOwnDefault(schema: GeneratedJsonSchema): boolean {\n return Object.prototype.hasOwnProperty.call(schema, 'default')\n}\n\nfunction allowsNull(schema: GeneratedJsonSchema): boolean {\n return schema.type === 'null' || (Array.isArray(schema.type) && schema.type.includes('null'))\n || !!schema.anyOf?.some(item => item.type === 'null')\n}\n\nfunction humanize(value: string): string {\n return value.replace(/[_-]+/g, ' ').replace(/^\\w/, character => character.toUpperCase())\n}\n","<script setup lang=\"ts\">\n/**\n * Standard generated workspace for a plugin that exposes an SDK job manifest.\n *\n * @example Recommended\n * ```vue\n * <GeneratedPluginView base-url=\"/api/peak-qc\" />\n * ```\n */\nimport { computed, onMounted, provide, reactive, ref, watch } from 'vue'\n\nimport { generatedJobDefaults, generatedJobFormSchema, normalizeGeneratedJobInput } from '../generated/schema'\nimport type { FormSchema } from '../types/form-builder'\nimport type {\n GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\nimport {\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n} from '../composables/useJobsEndpoint'\nimport AlertBox from './AlertBox.vue'\nimport EmptyState from './EmptyState.vue'\nimport GeneratedResultRenderer from './GeneratedResultRenderer.vue'\nimport JobsStatusTray from './JobsStatusTray.vue'\nimport LoadingSpinner from './LoadingSpinner.vue'\nimport PluginWorkspaceView from './PluginWorkspaceView.vue'\nimport { GENERATED_JOBS_API_KEY } from './internal/generatedJobsApi'\nimport { definePluginWorkspaceView } from '../composables/componentSpecs'\nimport { providePluginIdentity } from '../composables/pluginIdentity'\n\ninterface Props {\n baseUrl: string\n showStandaloneLabel?: boolean\n transport?: GeneratedAnalysisTransport\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showStandaloneLabel: false,\n})\n\nconst generated = useJobsEndpoint({\n baseUrl: props.baseUrl,\n transport: props.transport,\n manifest: true,\n})\nprovide(GENERATED_JOBS_API_KEY, { baseUrl: props.baseUrl, transport: props.transport })\nconst activeDefinitionId = ref('')\nconst selectedJobId = ref('')\nconst valuesByDefinition = reactive<Record<string, Record<string, unknown>>>({})\nconst definitions = computed(() => generated.manifest.value?.jobs ?? [])\nconst activeDefinition = computed(() => (\n definitions.value.find(definition => definition.id === activeDefinitionId.value) ?? null\n))\n\nconst pillNav = computed<PillNavItem[]>(() => definitions.value.map(definition => ({\n id: definition.id,\n label: definition.title,\n})))\n\nconst panels = computed<Record<string, SidebarToolSection[]>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, [{\n id: definition.id,\n label: 'Parameters',\n subtitle: resourceSummary(definition),\n defaultOpen: true,\n }]]),\n))\n\nconst forms = computed<Record<string, FormSchema>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, generatedJobFormSchema(definition)]),\n))\n\nconst workspace = computed(() => definePluginWorkspaceView({\n title: generated.manifest.value?.ui.title ?? 'Analysis',\n subtitle: generated.manifest.value?.ui.subtitle || generated.manifest.value?.ui.description,\n // The platform shell renders the toasts around this view.\n toasts: false,\n topBar: {\n pills: pillNav.value,\n settings: false,\n standaloneLabel: props.showStandaloneLabel ? 'Standalone' : false,\n },\n sidebar: { title: 'Parameters', panels: panels.value, forms: forms.value },\n}))\n\n// Seeds the standalone top bar icon; the title and subtitle above win over the seeded text.\nwatch(() => generated.manifest.value?.ui, (ui) => {\n if (ui) providePluginIdentity({ plugin: { name: ui.title, subtitle: ui.subtitle, description: ui.description, icon: ui.icon } })\n}, { immediate: true })\n\nconst currentValues = computed(() => valuesByDefinition[activeDefinitionId.value] ?? {})\nconst currentJob = computed(() => {\n const currentSessionId = generated.session.value?.id\n const currentDefinitionId = activeDefinitionId.value\n const selected = generated.jobs.value.find(candidate => (\n candidate.job_id === selectedJobId.value\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n return selected ?? generated.jobs.value.find(candidate => (\n candidate.session_id === currentSessionId\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n})\nconst currentResult = computed<GeneratedAnalysisResult | null>(() => (\n currentJob.value ? generated.resultForJob(currentJob.value.job_id) : null\n))\n\nwatch(definitions, (nextDefinitions) => {\n for (const definition of nextDefinitions) {\n valuesByDefinition[definition.id] ??= generatedJobDefaults(definition)\n }\n if (!nextDefinitions.some(definition => definition.id === activeDefinitionId.value)) {\n activeDefinitionId.value = nextDefinitions[0]?.id ?? ''\n }\n}, { immediate: true })\n\nwatch(currentJob, (job) => {\n if (job) void generated.result(job)\n}, { immediate: true })\n\nfunction updateValues(values: Record<string, unknown>): void {\n if (activeDefinitionId.value) valuesByDefinition[activeDefinitionId.value] = { ...values }\n}\n\nasync function submitJob(sectionId: string, values: Record<string, unknown>): Promise<void> {\n const definition = definitions.value.find(candidate => candidate.id === sectionId)\n if (!definition) return\n selectedJobId.value = ''\n valuesByDefinition[definition.id] = { ...values }\n await generated.submit(definition.id, normalizeGeneratedJobInput(definition, values))\n}\n\nfunction selectJob(job: GeneratedAnalysisJob): void {\n selectedJobId.value = job.job_id\n activeDefinitionId.value = String(job.metadata.definition_id ?? activeDefinitionId.value)\n}\n\nfunction resourceSummary(definition: GeneratedJobDefinition): string {\n if (definition.lifecycle === 'service' || definition.profile?.kind === 'service') {\n return 'Host service'\n }\n if (definition.lifecycle === 'staged' || definition.profile?.kind === 'staged') {\n return 'Staged upload'\n }\n return `Up to ${definition.cpu} CPU`\n}\n\nonMounted(() => {\n void generated.refresh().catch(() => undefined)\n})\n</script>\n\n<template>\n <PluginWorkspaceView\n v-model:view=\"activeDefinitionId\"\n :spec=\"workspace\"\n :values=\"currentValues\"\n :form-loading=\"generated.isSubmitting.value\"\n :form-disabled=\"generated.isSubmitting.value\"\n @update:values=\"updateValues\"\n @form-submit=\"submitJob\"\n >\n <main class=\"mint-generated-workspace\">\n <div v-if=\"generated.isLoading.value\" class=\"mint-generated-workspace__loading\">\n <LoadingSpinner size=\"lg\" />\n <span>Loading analysis workspace</span>\n </div>\n\n <template v-else>\n <AlertBox v-if=\"generated.error.value\" tone=\"error\">{{ generated.error.value }}</AlertBox>\n\n <header v-if=\"activeDefinition\" class=\"mint-generated-workspace__header\">\n <div>\n <p class=\"mint-generated-workspace__eyebrow\">Analysis result</p>\n <h1>{{ activeDefinition.title }}</h1>\n <p v-if=\"activeDefinition.description\">{{ activeDefinition.description }}</p>\n </div>\n <div class=\"mint-generated-workspace__resources\" aria-label=\"Job resource requirements\">\n <span>{{ resourceSummary(activeDefinition) }}</span>\n </div>\n </header>\n\n <section class=\"mint-generated-workspace__result\">\n <GeneratedResultRenderer\n v-if=\"currentResult\"\n :result=\"currentResult\"\n />\n <EmptyState\n v-else\n title=\"No result yet\"\n description=\"Set the parameters and run the analysis. Jobs continue independently if you switch tabs.\"\n size=\"md\"\n />\n </section>\n </template>\n\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\n </main>\n </PluginWorkspaceView>\n</template>\n\n<style scoped>\n.mint-generated-workspace {\n position: relative;\n min-width: 0;\n min-height: calc(100vh - 5rem);\n padding: clamp(1rem, 2.5vw, 2.5rem);\n background: var(--bg-primary);\n}\n\n.mint-generated-workspace__loading {\n display: flex;\n min-height: 24rem;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1.5rem;\n max-width: 76rem;\n margin: 0 auto 1.25rem;\n}\n\n.mint-generated-workspace__header h1 {\n margin: 0;\n color: var(--text-primary);\n font-size: clamp(1.35rem, 2vw, 1.8rem);\n line-height: 1.2;\n}\n\n.mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {\n margin: 0.4rem 0 0;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__eyebrow {\n margin: 0 0 0.35rem;\n color: var(--text-secondary);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n.mint-generated-workspace__resources {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 0.4rem;\n}\n\n.mint-generated-workspace__resources span {\n padding: 0.3rem 0.55rem;\n border: 1px solid var(--border-color);\n border-radius: 999px;\n background: var(--bg-secondary);\n color: var(--text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.mint-generated-workspace__result {\n max-width: 76rem;\n min-height: 24rem;\n margin: 0 auto;\n padding: clamp(1rem, 2vw, 1.75rem);\n border: 1px solid var(--border-color);\n border-radius: 1rem;\n background: var(--bg-secondary);\n box-shadow: var(--shadow-sm);\n}\n\n@media (max-width: 640px) {\n .mint-generated-workspace__header {\n flex-direction: column;\n }\n\n .mint-generated-workspace__resources {\n justify-content: flex-start;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Standard generated workspace for a plugin that exposes an SDK job manifest.\n *\n * @example Recommended\n * ```vue\n * <GeneratedPluginView base-url=\"/api/peak-qc\" />\n * ```\n */\nimport { computed, onMounted, provide, reactive, ref, watch } from 'vue'\n\nimport { generatedJobDefaults, generatedJobFormSchema, normalizeGeneratedJobInput } from '../generated/schema'\nimport type { FormSchema } from '../types/form-builder'\nimport type {\n GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\nimport {\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n} from '../composables/useJobsEndpoint'\nimport AlertBox from './AlertBox.vue'\nimport EmptyState from './EmptyState.vue'\nimport GeneratedResultRenderer from './GeneratedResultRenderer.vue'\nimport JobsStatusTray from './JobsStatusTray.vue'\nimport LoadingSpinner from './LoadingSpinner.vue'\nimport PluginWorkspaceView from './PluginWorkspaceView.vue'\nimport { GENERATED_JOBS_API_KEY } from './internal/generatedJobsApi'\nimport { definePluginWorkspaceView } from '../composables/componentSpecs'\nimport { providePluginIdentity } from '../composables/pluginIdentity'\n\ninterface Props {\n baseUrl: string\n showStandaloneLabel?: boolean\n transport?: GeneratedAnalysisTransport\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showStandaloneLabel: false,\n})\n\nconst generated = useJobsEndpoint({\n baseUrl: props.baseUrl,\n transport: props.transport,\n manifest: true,\n})\nprovide(GENERATED_JOBS_API_KEY, { baseUrl: props.baseUrl, transport: props.transport })\nconst activeDefinitionId = ref('')\nconst selectedJobId = ref('')\nconst valuesByDefinition = reactive<Record<string, Record<string, unknown>>>({})\nconst definitions = computed(() => generated.manifest.value?.jobs ?? [])\nconst activeDefinition = computed(() => (\n definitions.value.find(definition => definition.id === activeDefinitionId.value) ?? null\n))\n\nconst pillNav = computed<PillNavItem[]>(() => definitions.value.map(definition => ({\n id: definition.id,\n label: definition.title,\n})))\n\nconst panels = computed<Record<string, SidebarToolSection[]>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, [{\n id: definition.id,\n label: 'Parameters',\n subtitle: resourceSummary(definition),\n defaultOpen: true,\n }]]),\n))\n\nconst forms = computed<Record<string, FormSchema>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, generatedJobFormSchema(definition)]),\n))\n\nconst workspace = computed(() => definePluginWorkspaceView({\n title: generated.manifest.value?.ui.title ?? 'Analysis',\n subtitle: generated.manifest.value?.ui.subtitle || generated.manifest.value?.ui.description,\n // The platform shell renders the toasts around this view.\n toasts: false,\n topBar: {\n pills: pillNav.value,\n settings: false,\n standaloneLabel: props.showStandaloneLabel ? 'Standalone' : false,\n },\n sidebar: { title: 'Parameters', panels: panels.value, forms: forms.value },\n}))\n\n// Seeds the standalone top bar icon; the title and subtitle above win over the seeded text.\nwatch(() => generated.manifest.value?.ui, (ui) => {\n if (ui) providePluginIdentity({ plugin: { name: ui.title, subtitle: ui.subtitle, description: ui.description, icon: ui.icon } })\n}, { immediate: true })\n\nconst currentValues = computed(() => valuesByDefinition[activeDefinitionId.value] ?? {})\nconst currentJob = computed(() => {\n const currentSessionId = generated.session.value?.id\n const currentDefinitionId = activeDefinitionId.value\n const selected = generated.jobs.value.find(candidate => (\n candidate.job_id === selectedJobId.value\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n return selected ?? generated.jobs.value.find(candidate => (\n candidate.session_id === currentSessionId\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n})\nconst currentResult = computed<GeneratedAnalysisResult | null>(() => (\n currentJob.value ? generated.resultForJob(currentJob.value.job_id) : null\n))\n\nwatch(definitions, (nextDefinitions) => {\n for (const definition of nextDefinitions) {\n valuesByDefinition[definition.id] ??= generatedJobDefaults(definition)\n }\n if (!nextDefinitions.some(definition => definition.id === activeDefinitionId.value)) {\n activeDefinitionId.value = nextDefinitions[0]?.id ?? ''\n }\n}, { immediate: true })\n\nwatch(currentJob, (job) => {\n if (job) void generated.result(job)\n}, { immediate: true })\n\nfunction updateValues(values: Record<string, unknown>): void {\n if (activeDefinitionId.value) valuesByDefinition[activeDefinitionId.value] = { ...values }\n}\n\nasync function submitJob(sectionId: string, values: Record<string, unknown>): Promise<void> {\n const definition = definitions.value.find(candidate => candidate.id === sectionId)\n if (!definition) return\n selectedJobId.value = ''\n valuesByDefinition[definition.id] = { ...values }\n await generated.submit(definition.id, normalizeGeneratedJobInput(definition, values))\n}\n\nfunction selectJob(job: GeneratedAnalysisJob): void {\n selectedJobId.value = job.job_id\n activeDefinitionId.value = String(job.metadata.definition_id ?? activeDefinitionId.value)\n}\n\nfunction resourceSummary(definition: GeneratedJobDefinition): string {\n if (definition.lifecycle === 'service' || definition.profile?.kind === 'service') {\n return 'Host service'\n }\n if (definition.lifecycle === 'staged' || definition.profile?.kind === 'staged') {\n return 'Staged upload'\n }\n return `Up to ${definition.cpu} CPU`\n}\n\nonMounted(() => {\n void generated.refresh().catch(() => undefined)\n})\n</script>\n\n<template>\n <PluginWorkspaceView\n v-model:view=\"activeDefinitionId\"\n :spec=\"workspace\"\n :values=\"currentValues\"\n :form-loading=\"generated.isSubmitting.value\"\n :form-disabled=\"generated.isSubmitting.value\"\n @update:values=\"updateValues\"\n @form-submit=\"submitJob\"\n >\n <main class=\"mint-generated-workspace\">\n <div v-if=\"generated.isLoading.value\" class=\"mint-generated-workspace__loading\">\n <LoadingSpinner size=\"lg\" />\n <span>Loading analysis workspace</span>\n </div>\n\n <template v-else>\n <AlertBox v-if=\"generated.error.value\" tone=\"error\">{{ generated.error.value }}</AlertBox>\n\n <header v-if=\"activeDefinition\" class=\"mint-generated-workspace__header\">\n <div>\n <p class=\"mint-generated-workspace__eyebrow\">Analysis result</p>\n <h1>{{ activeDefinition.title }}</h1>\n <p v-if=\"activeDefinition.description\">{{ activeDefinition.description }}</p>\n </div>\n <div class=\"mint-generated-workspace__resources\" aria-label=\"Job resource requirements\">\n <span>{{ resourceSummary(activeDefinition) }}</span>\n </div>\n </header>\n\n <section class=\"mint-generated-workspace__result\">\n <GeneratedResultRenderer\n v-if=\"currentResult\"\n :result=\"currentResult\"\n />\n <EmptyState\n v-else\n title=\"No result yet\"\n description=\"Set the parameters and run the analysis. Jobs continue independently if you switch tabs.\"\n size=\"md\"\n />\n </section>\n </template>\n\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\n </main>\n </PluginWorkspaceView>\n</template>\n\n<style scoped>\n.mint-generated-workspace {\n position: relative;\n min-width: 0;\n min-height: calc(100vh - 5rem);\n padding: clamp(1rem, 2.5vw, 2.5rem);\n background: var(--bg-primary);\n}\n\n.mint-generated-workspace__loading {\n display: flex;\n min-height: 24rem;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1.5rem;\n max-width: 76rem;\n margin: 0 auto 1.25rem;\n}\n\n.mint-generated-workspace__header h1 {\n margin: 0;\n color: var(--text-primary);\n font-size: clamp(1.35rem, 2vw, 1.8rem);\n line-height: 1.2;\n}\n\n.mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {\n margin: 0.4rem 0 0;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__eyebrow {\n margin: 0 0 0.35rem;\n color: var(--text-secondary);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n.mint-generated-workspace__resources {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 0.4rem;\n}\n\n.mint-generated-workspace__resources span {\n padding: 0.3rem 0.55rem;\n border: 1px solid var(--border-color);\n border-radius: 999px;\n background: var(--bg-secondary);\n color: var(--text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.mint-generated-workspace__result {\n max-width: 76rem;\n min-height: 24rem;\n margin: 0 auto;\n padding: clamp(1rem, 2vw, 1.75rem);\n border: 1px solid var(--border-color);\n border-radius: 1rem;\n background: var(--bg-secondary);\n box-shadow: var(--shadow-sm);\n}\n\n@media (max-width: 640px) {\n .mint-generated-workspace__header {\n flex-direction: column;\n }\n\n .mint-generated-workspace__resources {\n justify-content: flex-start;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/** PlateEditor holding its own copy of the plates (useRackEditor), for ComponentBindingRenderer bindings. */\nimport { watch } from 'vue'\nimport type { PlateEditorSpec, Rack } from '../../types'\nimport { useRackEditor } from '../../composables/useRackEditor'\nimport PlateEditor from '../PlateEditor.vue'\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: Rack[]\n activeRack?: string\n spec?: PlateEditorSpec\n}>()\n\nconst editor = useRackEditor(props.modelValue)\nconst { racks, activeRackId, plateEditorListeners, canUndo, canRedo } = editor\n// A new binding (template reloaded) replaces the local copy and its history, then reselects: the\n// activeRack watch may have run first, before its rack existed.\nwatch(() => props.modelValue, (next) => {\n racks.value = next.map(rack => ({ ...rack, wells: { ...rack.wells } }))\n editor.clearHistory()\n if (props.activeRack) editor.setActiveRack(props.activeRack)\n})\nwatch(() => props.activeRack, (id) => { if (id) editor.setActiveRack(id) }, { immediate: true })\n</script>\n\n<template>\n <PlateEditor\n v-bind=\"$attrs\"\n :spec=\"{ history: true, ...spec }\"\n :model-value=\"racks\"\n :active-rack=\"activeRackId\"\n :can-undo=\"canUndo\"\n :can-redo=\"canRedo\"\n v-on=\"plateEditorListeners\"\n />\n</template>\n","<script setup lang=\"ts\">\n/** PlateEditor holding its own copy of the plates (useRackEditor), for ComponentBindingRenderer bindings. */\nimport { watch } from 'vue'\nimport type { PlateEditorSpec, Rack } from '../../types'\nimport { useRackEditor } from '../../composables/useRackEditor'\nimport PlateEditor from '../PlateEditor.vue'\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: Rack[]\n activeRack?: string\n spec?: PlateEditorSpec\n}>()\n\nconst editor = useRackEditor(props.modelValue)\nconst { racks, activeRackId, plateEditorListeners, canUndo, canRedo } = editor\n// A new binding (template reloaded) replaces the local copy and its history, then reselects: the\n// activeRack watch may have run first, before its rack existed.\nwatch(() => props.modelValue, (next) => {\n racks.value = next.map(rack => ({ ...rack, wells: { ...rack.wells } }))\n editor.clearHistory()\n if (props.activeRack) editor.setActiveRack(props.activeRack)\n})\nwatch(() => props.activeRack, (id) => { if (id) editor.setActiveRack(id) }, { immediate: true })\n</script>\n\n<template>\n <PlateEditor\n v-bind=\"$attrs\"\n :spec=\"{ history: true, ...spec }\"\n :model-value=\"racks\"\n :active-rack=\"activeRackId\"\n :can-undo=\"canUndo\"\n :can-redo=\"canRedo\"\n v-on=\"plateEditorListeners\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Render generated SDK component bindings such as WellPlate, DoseCalculator, DataFrame, and PlateEditor.\n *\n * @example Recommended\n * ```vue\n * <ComponentBindingRenderer :bindings=\"workspace.componentBindings.value\" />\n * ```\n */\nimport { computed, type Component } from 'vue'\nimport DataFrame from './DataFrame.vue'\nimport DoseCalculator from './DoseCalculator.vue'\nimport PlateEditorBindingInternal from './internal/PlateEditorBindingInternal.vue'\nimport ScheduleCalendar from './ScheduleCalendar.vue'\nimport WellPlate from './WellPlate.vue'\nimport { isRecord } from '../utils/records'\n\nexport interface ComponentBindingRendererBinding {\n id?: string\n component: string\n props?: Record<string, unknown> | readonly string[]\n propsObject?: Record<string, unknown>\n description?: string\n}\n\ntype ComponentBindingRendererLayout = 'grid' | 'stack'\n\ninterface Props {\n /** Single generated SDK component binding to render. */\n binding?: ComponentBindingRendererBinding\n /** Generated SDK component bindings to render. */\n bindings?: ComponentBindingRendererBinding[]\n /** Optional allow-list of component names, for example ['WellPlate', 'DataFrame']. */\n include?: string[]\n /** Optional deny-list of component names. */\n exclude?: string[]\n /** Compact child component sizing. */\n dense?: boolean\n /** Prefer preview-safe props for editable components. */\n readonly?: boolean\n /** Show component labels above each rendered component. */\n showHeaders?: boolean\n /** Show binding descriptions in each header. */\n showDescriptions?: boolean\n /** Grid or vertical stack layout. */\n layout?: ComponentBindingRendererLayout\n /** Message shown when no binding can be rendered. */\n emptyText?: string\n}\n\ntype RenderableBinding = ComponentBindingRendererBinding & {\n id: string\n componentImpl: Component\n normalizedProps: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n binding: undefined,\n bindings: () => [],\n include: () => [],\n exclude: () => [],\n dense: false,\n readonly: true,\n showHeaders: true,\n showDescriptions: true,\n layout: 'grid',\n emptyText: 'No renderable SDK component bindings.',\n})\n\nconst componentRegistry: Record<string, Component> = {\n DataFrame,\n DoseCalculator,\n // Holds its own copy of the plates: PlateEditor itself is controlled.\n PlateEditor: PlateEditorBindingInternal,\n ScheduleCalendar,\n WellPlate,\n}\n\nconst inputBindings = computed<ComponentBindingRendererBinding[]>(() => [\n ...(props.binding ? [props.binding] : []),\n ...props.bindings,\n])\n\nconst renderableBindings = computed<RenderableBinding[]>(() =>\n inputBindings.value\n .filter(binding => isIncluded(binding.component))\n .map((binding, index) => {\n const componentImpl = componentRegistry[binding.component]\n if (!componentImpl) return null\n return {\n ...binding,\n id: binding.id ?? `${binding.component}-${index + 1}`,\n componentImpl,\n normalizedProps: normalizeProps(binding),\n }\n })\n .filter((binding): binding is RenderableBinding => binding !== null)\n)\n\nconst rendererClasses = computed(() => [\n 'mint-component-binding-renderer',\n `mint-component-binding-renderer--${props.layout}`,\n props.dense ? 'mint-component-binding-renderer--dense' : '',\n])\n\nfunction isIncluded(componentName: string): boolean {\n if (props.include.length > 0 && !props.include.includes(componentName)) return false\n return !props.exclude.includes(componentName)\n}\n\nfunction baseProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n if (binding.propsObject) return { ...binding.propsObject }\n if (isRecord(binding.props)) return { ...binding.props }\n return {}\n}\n\nfunction normalizeProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n const base = baseProps(binding)\n\n switch (binding.component) {\n case 'WellPlate':\n case 'PlateEditor': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: { ...spec, size: props.dense ? 'md' : (spec.size ?? 'fill') },\n readonly: props.readonly || Boolean(base.readonly),\n }\n }\n case 'DataFrame': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: {\n ...spec,\n size: props.dense ? 'sm' : (spec.size ?? 'md'),\n maxHeight: spec.maxHeight ?? (props.dense ? '280px' : undefined),\n },\n }\n }\n case 'ScheduleCalendar':\n return {\n ...base,\n readonly: props.readonly || Boolean(base.readonly),\n showNavigation: props.dense ? false : (base.showNavigation ?? true),\n showViewToggle: props.dense ? false : (base.showViewToggle ?? true),\n }\n default:\n return base\n }\n}\n\n</script>\n\n<template>\n <div :class=\"rendererClasses\">\n <section\n v-for=\"renderableBinding in renderableBindings\"\n :key=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__item\"\n :data-component-binding-id=\"renderableBinding.id\"\n >\n <header\n v-if=\"showHeaders\"\n class=\"mint-component-binding-renderer__header\"\n >\n <div class=\"mint-component-binding-renderer__title-group\">\n <p class=\"mint-component-binding-renderer__component\">\n {{ renderableBinding.component }}\n </p>\n <p\n v-if=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__source\"\n >\n {{ renderableBinding.id }}\n </p>\n </div>\n <p\n v-if=\"showDescriptions && renderableBinding.description\"\n class=\"mint-component-binding-renderer__description\"\n >\n {{ renderableBinding.description }}\n </p>\n </header>\n\n <div class=\"mint-component-binding-renderer__body\">\n <component\n :is=\"renderableBinding.componentImpl\"\n v-bind=\"renderableBinding.normalizedProps\"\n />\n </div>\n </section>\n\n <p\n v-if=\"renderableBindings.length === 0\"\n class=\"mint-component-binding-renderer__empty\"\n >\n {{ emptyText }}\n </p>\n </div>\n</template>\n\n<style scoped>\n.mint-component-binding-renderer {\n display: grid;\n gap: 1rem;\n min-width: 0;\n}\n\n.mint-component-binding-renderer--grid {\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));\n}\n\n.mint-component-binding-renderer--stack {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.mint-component-binding-renderer--dense {\n gap: 0.75rem;\n}\n\n.mint-component-binding-renderer__item {\n min-width: 0;\n overflow: hidden;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-card, #ffffff);\n box-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / 0.06));\n}\n\n.mint-component-binding-renderer__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n background: var(--bg-secondary, #f8fafc);\n}\n\n.mint-component-binding-renderer__title-group {\n min-width: 0;\n}\n\n.mint-component-binding-renderer__component {\n margin: 0;\n color: var(--text-primary, #0f172a);\n font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);\n font-size: 0.8125rem;\n font-weight: 600;\n}\n\n.mint-component-binding-renderer__source,\n.mint-component-binding-renderer__description,\n.mint-component-binding-renderer__empty {\n margin: 0;\n color: var(--text-secondary, #475569);\n font-size: 0.75rem;\n line-height: 1.4;\n}\n\n.mint-component-binding-renderer__description {\n max-width: 24rem;\n text-align: right;\n}\n\n.mint-component-binding-renderer__body {\n min-width: 0;\n padding: 1rem;\n}\n\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__header,\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__body {\n padding: 0.75rem;\n}\n\n.mint-component-binding-renderer__empty {\n padding: 1rem;\n border: 1px dashed var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-secondary, #f8fafc);\n text-align: center;\n}\n\n@media (max-width: 720px) {\n .mint-component-binding-renderer__header {\n display: block;\n }\n\n .mint-component-binding-renderer__description {\n max-width: none;\n margin-top: 0.25rem;\n text-align: left;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Render generated SDK component bindings such as WellPlate, DoseCalculator, DataFrame, and PlateEditor.\n *\n * @example Recommended\n * ```vue\n * <ComponentBindingRenderer :bindings=\"workspace.componentBindings.value\" />\n * ```\n */\nimport { computed, type Component } from 'vue'\nimport DataFrame from './DataFrame.vue'\nimport DoseCalculator from './DoseCalculator.vue'\nimport PlateEditorBindingInternal from './internal/PlateEditorBindingInternal.vue'\nimport ScheduleCalendar from './ScheduleCalendar.vue'\nimport WellPlate from './WellPlate.vue'\nimport { isRecord } from '../utils/records'\n\nexport interface ComponentBindingRendererBinding {\n id?: string\n component: string\n props?: Record<string, unknown> | readonly string[]\n propsObject?: Record<string, unknown>\n description?: string\n}\n\ntype ComponentBindingRendererLayout = 'grid' | 'stack'\n\ninterface Props {\n /** Single generated SDK component binding to render. */\n binding?: ComponentBindingRendererBinding\n /** Generated SDK component bindings to render. */\n bindings?: ComponentBindingRendererBinding[]\n /** Optional allow-list of component names, for example ['WellPlate', 'DataFrame']. */\n include?: string[]\n /** Optional deny-list of component names. */\n exclude?: string[]\n /** Compact child component sizing. */\n dense?: boolean\n /** Prefer preview-safe props for editable components. */\n readonly?: boolean\n /** Show component labels above each rendered component. */\n showHeaders?: boolean\n /** Show binding descriptions in each header. */\n showDescriptions?: boolean\n /** Grid or vertical stack layout. */\n layout?: ComponentBindingRendererLayout\n /** Message shown when no binding can be rendered. */\n emptyText?: string\n}\n\ntype RenderableBinding = ComponentBindingRendererBinding & {\n id: string\n componentImpl: Component\n normalizedProps: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n binding: undefined,\n bindings: () => [],\n include: () => [],\n exclude: () => [],\n dense: false,\n readonly: true,\n showHeaders: true,\n showDescriptions: true,\n layout: 'grid',\n emptyText: 'No renderable SDK component bindings.',\n})\n\nconst componentRegistry: Record<string, Component> = {\n DataFrame,\n DoseCalculator,\n // Holds its own copy of the plates: PlateEditor itself is controlled.\n PlateEditor: PlateEditorBindingInternal,\n ScheduleCalendar,\n WellPlate,\n}\n\nconst inputBindings = computed<ComponentBindingRendererBinding[]>(() => [\n ...(props.binding ? [props.binding] : []),\n ...props.bindings,\n])\n\nconst renderableBindings = computed<RenderableBinding[]>(() =>\n inputBindings.value\n .filter(binding => isIncluded(binding.component))\n .map((binding, index) => {\n const componentImpl = componentRegistry[binding.component]\n if (!componentImpl) return null\n return {\n ...binding,\n id: binding.id ?? `${binding.component}-${index + 1}`,\n componentImpl,\n normalizedProps: normalizeProps(binding),\n }\n })\n .filter((binding): binding is RenderableBinding => binding !== null)\n)\n\nconst rendererClasses = computed(() => [\n 'mint-component-binding-renderer',\n `mint-component-binding-renderer--${props.layout}`,\n props.dense ? 'mint-component-binding-renderer--dense' : '',\n])\n\nfunction isIncluded(componentName: string): boolean {\n if (props.include.length > 0 && !props.include.includes(componentName)) return false\n return !props.exclude.includes(componentName)\n}\n\nfunction baseProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n if (binding.propsObject) return { ...binding.propsObject }\n if (isRecord(binding.props)) return { ...binding.props }\n return {}\n}\n\nfunction normalizeProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n const base = baseProps(binding)\n\n switch (binding.component) {\n case 'WellPlate':\n case 'PlateEditor': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: { ...spec, size: props.dense ? 'md' : (spec.size ?? 'fill') },\n readonly: props.readonly || Boolean(base.readonly),\n }\n }\n case 'DataFrame': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: {\n ...spec,\n size: props.dense ? 'sm' : (spec.size ?? 'md'),\n maxHeight: spec.maxHeight ?? (props.dense ? '280px' : undefined),\n },\n }\n }\n case 'ScheduleCalendar':\n return {\n ...base,\n readonly: props.readonly || Boolean(base.readonly),\n showNavigation: props.dense ? false : (base.showNavigation ?? true),\n showViewToggle: props.dense ? false : (base.showViewToggle ?? true),\n }\n default:\n return base\n }\n}\n\n</script>\n\n<template>\n <div :class=\"rendererClasses\">\n <section\n v-for=\"renderableBinding in renderableBindings\"\n :key=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__item\"\n :data-component-binding-id=\"renderableBinding.id\"\n >\n <header\n v-if=\"showHeaders\"\n class=\"mint-component-binding-renderer__header\"\n >\n <div class=\"mint-component-binding-renderer__title-group\">\n <p class=\"mint-component-binding-renderer__component\">\n {{ renderableBinding.component }}\n </p>\n <p\n v-if=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__source\"\n >\n {{ renderableBinding.id }}\n </p>\n </div>\n <p\n v-if=\"showDescriptions && renderableBinding.description\"\n class=\"mint-component-binding-renderer__description\"\n >\n {{ renderableBinding.description }}\n </p>\n </header>\n\n <div class=\"mint-component-binding-renderer__body\">\n <component\n :is=\"renderableBinding.componentImpl\"\n v-bind=\"renderableBinding.normalizedProps\"\n />\n </div>\n </section>\n\n <p\n v-if=\"renderableBindings.length === 0\"\n class=\"mint-component-binding-renderer__empty\"\n >\n {{ emptyText }}\n </p>\n </div>\n</template>\n\n<style scoped>\n.mint-component-binding-renderer {\n display: grid;\n gap: 1rem;\n min-width: 0;\n}\n\n.mint-component-binding-renderer--grid {\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));\n}\n\n.mint-component-binding-renderer--stack {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.mint-component-binding-renderer--dense {\n gap: 0.75rem;\n}\n\n.mint-component-binding-renderer__item {\n min-width: 0;\n overflow: hidden;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-card, #ffffff);\n box-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / 0.06));\n}\n\n.mint-component-binding-renderer__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n background: var(--bg-secondary, #f8fafc);\n}\n\n.mint-component-binding-renderer__title-group {\n min-width: 0;\n}\n\n.mint-component-binding-renderer__component {\n margin: 0;\n color: var(--text-primary, #0f172a);\n font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);\n font-size: 0.8125rem;\n font-weight: 600;\n}\n\n.mint-component-binding-renderer__source,\n.mint-component-binding-renderer__description,\n.mint-component-binding-renderer__empty {\n margin: 0;\n color: var(--text-secondary, #475569);\n font-size: 0.75rem;\n line-height: 1.4;\n}\n\n.mint-component-binding-renderer__description {\n max-width: 24rem;\n text-align: right;\n}\n\n.mint-component-binding-renderer__body {\n min-width: 0;\n padding: 1rem;\n}\n\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__header,\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__body {\n padding: 0.75rem;\n}\n\n.mint-component-binding-renderer__empty {\n padding: 1rem;\n border: 1px dashed var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-secondary, #f8fafc);\n text-align: center;\n}\n\n@media (max-width: 720px) {\n .mint-component-binding-renderer__header {\n display: block;\n }\n\n .mint-component-binding-renderer__description {\n max-width: none;\n margin-top: 0.25rem;\n text-align: left;\n }\n}\n</style>\n","<script setup lang=\"ts\">\nimport { RefreshCw } from 'lucide-vue-next'\n\ndefineProps<{\n visible: boolean\n}>()\n\nconst emit = defineEmits<{\n reload: []\n}>()\n</script>\n\n<template>\n <div v-if=\"visible\" class=\"mint-runtime-update\" role=\"status\">\n <RefreshCw :size=\"16\" aria-hidden=\"true\" />\n <span>A new version is ready.</span>\n <button type=\"button\" @click=\"emit('reload')\">\n Reload now\n </button>\n </div>\n</template>\n\n<style scoped>\n.mint-runtime-update {\n position: fixed;\n right: 20px;\n bottom: 20px;\n z-index: 1200;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n color: var(--text-primary);\n background: var(--bg-card);\n border: 1px solid var(--border-color);\n border-radius: 10px;\n box-shadow: 0 10px 28px rgb(15 23 42 / 16%);\n font-size: 13px;\n font-weight: 500;\n}\n\n.mint-runtime-update button {\n padding: 5px 9px;\n color: var(--text-on-accent);\n background: var(--color-primary);\n border: 0;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { RefreshCw } from 'lucide-vue-next'\n\ndefineProps<{\n visible: boolean\n}>()\n\nconst emit = defineEmits<{\n reload: []\n}>()\n</script>\n\n<template>\n <div v-if=\"visible\" class=\"mint-runtime-update\" role=\"status\">\n <RefreshCw :size=\"16\" aria-hidden=\"true\" />\n <span>A new version is ready.</span>\n <button type=\"button\" @click=\"emit('reload')\">\n Reload now\n </button>\n </div>\n</template>\n\n<style scoped>\n.mint-runtime-update {\n position: fixed;\n right: 20px;\n bottom: 20px;\n z-index: 1200;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n color: var(--text-primary);\n background: var(--bg-card);\n border: 1px solid var(--border-color);\n border-radius: 10px;\n box-shadow: 0 10px 28px rgb(15 23 42 / 16%);\n font-size: 13px;\n font-weight: 500;\n}\n\n.mint-runtime-update button {\n padding: 5px 9px;\n color: var(--text-on-accent);\n background: var(--color-primary);\n border: 0;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n}\n</style>\n","import {\n getCurrentScope,\n onScopeDispose,\n readonly,\n ref,\n toValue,\n watch,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport { useApi } from './useApi'\nimport { currentPresence, subscribeRealtime, type RealtimeEvent } from './useRealtime'\n\n/**\n * What a viewer does on a topic. The platform accepts a fixed set per topic\n * kind: `experiment:{id}` takes all four labels, `project:{id}` only\n * `viewing` and `editing`. `editing` means a form with unsaved edits is open;\n * it is a hint, not a lock.\n */\nexport type PresenceActivity = 'viewing' | 'viewing_design' | 'viewing_results' | 'editing'\n\n/** One user with an open realtime stream on the topic. */\nexport interface PresenceViewer {\n user_id: string\n activity: PresenceActivity\n}\n\nexport interface UsePresenceReturn {\n /** The viewers, `editing` first, at most 20; the current user is included. Empty while the stream is closed. */\n viewers: Readonly<Ref<readonly PresenceViewer[]>>\n /** Every viewer, also those beyond the 20 in `viewers`. */\n count: Readonly<Ref<number>>\n /** True while the shared realtime stream is open. */\n connected: Readonly<Ref<boolean>>\n /** Unsubscribe; also runs when the calling component or effect scope is disposed. */\n stop: () => void\n}\n\n/**\n * Who else views an `experiment:{id}` or `project:{id}` topic (RFC #439).\n *\n * Built on `useRealtime`: the tab's open stream on the topic is its presence,\n * and `presence.changed` events update `viewers`. When `activity` is given,\n * the label is sent to `POST /api/presence/activity` when the call starts on\n * an open stream, each time the stream opens and each time the label changes;\n * `stop` (also the end of the calling scope) sets it back to `viewing`.\n * Without it, the platform shows the tab as `viewing`. Like `useRealtime`, it needs the platform's `realtime`\n * feature flag; check that flag first.\n *\n * @example\n * const { viewers } = usePresence(\n * () => `experiment:${id.value}`,\n * () => (dirty.value ? 'editing' : 'viewing'),\n * )\n */\nexport function usePresence(\n topic: MaybeRefOrGetter<string>,\n activity?: MaybeRefOrGetter<PresenceActivity>,\n): UsePresenceReturn {\n const viewers = ref<readonly PresenceViewer[]>([])\n const count = ref(0)\n const api = activity === undefined ? null : useApi({ baseUrl: '/api' })\n\n function report(label = toValue(activity)): void {\n // Presence is a hint: a failed report never reaches the view.\n api?.post('/presence/activity', { topic: toValue(topic), activity: label }).catch(() => {})\n }\n\n function show(event: RealtimeEvent | undefined): void {\n viewers.value = (event?.viewers ?? []) as PresenceViewer[]\n count.value = event?.count ?? 0\n }\n\n const realtime = subscribeRealtime(() => [toValue(topic)], (event) => {\n // ponytail: a resync after a queue overflow keeps the last viewers until\n // the next change; read the presence over REST here if that shows.\n if (event.type === 'resync') report()\n else if (event.type === 'presence.changed' && event.topic === toValue(topic)) show(event)\n }, true)\n\n // When the tab's open stream already views the topic, no open and no resync follow.\n function load(): void {\n const current = currentPresence(toValue(topic))\n show(current)\n if (current) report()\n }\n load()\n const stopTopic = watch(() => toValue(topic), load)\n // A closed stream shows nobody; the server sends the viewers again at the next open.\n const stopConnected = watch(realtime.connected, (open) => { if (!open) show(undefined) })\n // While the stream is closed the report waits for the resync of the next open.\n const stopActivity = watch(() => toValue(activity), () => {\n if (realtime.connected.value) report()\n })\n\n let stopped = false\n function stop(): void {\n if (stopped) return\n stopped = true\n stopTopic()\n stopConnected()\n stopActivity()\n // The stream can stay open on the topic for other callers: drop this caller's label.\n if (realtime.connected.value && toValue(activity) !== 'viewing') report('viewing')\n realtime.stop()\n }\n if (getCurrentScope()) onScopeDispose(stop)\n\n return { viewers: readonly(viewers), count: readonly(count), connected: realtime.connected, stop }\n}\n","import type { PresenceActivity } from '../composables/usePresence'\n\n/** One person on a presence topic, with the name to show. */\nexport interface PresencePerson {\n id: string\n name: string\n activity: PresenceActivity\n}\n\nexport interface PresenceArrangement {\n /** Every other person, `editing` first. */\n others: PresencePerson[]\n /** The people that get an avatar. */\n shown: PresencePerson[]\n /** The other people without an avatar (the `+N`). */\n overflow: number\n /** All other people, also those the platform did not list. */\n total: number\n}\n\nexport const PRESENCE_ACTIVITY_LABELS: Record<PresenceActivity, string> = {\n viewing: 'viewing',\n viewing_design: 'viewing design',\n viewing_results: 'viewing results',\n editing: 'editing',\n}\n\n/**\n * Remove the current user, sort `editing` first (the sort is stable, so the\n * platform order stays otherwise) and keep at most `max` avatars.\n * `count` is the platform's total, the current user included.\n */\nexport function arrangePresence(\n people: readonly PresencePerson[],\n options: { selfId?: string | null; count?: number; max?: number } = {},\n): PresenceArrangement {\n const max = options.max ?? 4\n const selfListed = people.some(person => person.id === options.selfId)\n const others = people\n .filter(person => person.id !== options.selfId)\n .sort((a, b) => Number(b.activity === 'editing') - Number(a.activity === 'editing'))\n // ponytail: past the platform's 20-viewer cap an unlisted current user counts as other.\n const total = Math.max(others.length, (options.count ?? people.length) - (selfListed ? 1 : 0))\n const shown = others.slice(0, max)\n return { others, shown, overflow: total - shown.length, total }\n}\n\n/** \"6 other people here: Alice Chen editing, Chen Li viewing design, and 4 more\". */\nexport function presenceSummary({ shown, overflow, total }: PresenceArrangement): string {\n const names = shown.map(person => `${person.name} ${PRESENCE_ACTIVITY_LABELS[person.activity]}`)\n if (overflow > 0) names.push(`and ${overflow} more`)\n return `${total} other ${total === 1 ? 'person' : 'people'} here: ${names.join(', ')}`\n}\n","<script setup lang=\"ts\">\n/** Who else is on a presence topic: at most `max` avatars (editing first), then `+N`; one button opens the list of each person and activity. */\nimport { computed, useId, useTemplateRef, watch, type Component } from 'vue'\nimport { ChartColumn, Eye, FlaskConical, Pencil } from 'lucide-vue-next'\nimport Avatar from './Avatar.vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { useEventListener } from '../composables/useEventListener'\nimport type { PresenceActivity } from '../composables/usePresence'\nimport {\n PRESENCE_ACTIVITY_LABELS,\n arrangePresence,\n presenceSummary,\n type PresencePerson,\n} from '../utils/presenceAvatars'\n\ninterface Props {\n /** The people on the topic, for example `usePresence().viewers` with names. */\n people: PresencePerson[]\n /** The current user; never shown. */\n selfId?: string | null\n /** All people on the topic (`usePresence().count`), when the list is capped. */\n count?: number\n /** Accessible name of the list. */\n label?: string\n /** Most avatars before `+N`. */\n max?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n selfId: null,\n count: undefined,\n label: 'People here',\n max: 4,\n})\n\nconst ACTIVITY_ICONS: Record<PresenceActivity, Component> = {\n viewing: Eye,\n viewing_design: FlaskConical,\n viewing_results: ChartColumn,\n editing: Pencil,\n}\n\nconst arrangement = computed(() => arrangePresence(props.people, {\n selfId: props.selfId,\n count: props.count,\n max: props.max,\n}))\nconst summary = computed(() => presenceSummary(arrangement.value))\nconst unlisted = computed(() => arrangement.value.total - arrangement.value.others.length)\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst { isOpen, toggle, close } = useDropdownState({\n rootRef: root,\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\n// Escape closes the list from anywhere, but takes the focus back to the button only from within it.\nuseEventListener(() => document, 'keydown', (event) => {\n if (event.key === 'Escape') close(root.value?.contains(event.target as Node) ?? false)\n})\n// The root unmounts when nobody else is here; the list must not reopen on its own when someone comes back.\nwatch(() => arrangement.value.total, (total) => { if (total === 0) close() })\nconst panelId = `mint-presence-${useId()}`\n</script>\n\n<template>\n <div v-if=\"arrangement.total > 0\" ref=\"root\" class=\"mint-presence\">\n <button\n ref=\"trigger\"\n type=\"button\"\n class=\"mint-presence__trigger\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? panelId : undefined\"\n :aria-label=\"summary\"\n @click=\"toggle\"\n >\n <span class=\"mint-presence__stack\" aria-hidden=\"true\">\n <span\n v-for=\"person in arrangement.shown\"\n :key=\"person.id\"\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span v-if=\"arrangement.overflow > 0\" class=\"mint-presence__more\">+{{ arrangement.overflow }}</span>\n </span>\n </button>\n\n <div v-if=\"isOpen\" :id=\"panelId\" class=\"mint-popover mint-presence__panel\">\n <div class=\"mint-presence__head\">Here now <span class=\"mint-presence__count\">{{ arrangement.total }}</span></div>\n <ul class=\"mint-presence__list\" :aria-label=\"label\">\n <li v-for=\"person in arrangement.others\" :key=\"person.id\" class=\"mint-presence__row\">\n <span\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n aria-hidden=\"true\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span class=\"mint-presence__name\">{{ person.name }}</span>\n <span :class=\"['mint-presence__activity', { 'mint-presence__activity--editing': person.activity === 'editing' }]\">\n <component :is=\"ACTIVITY_ICONS[person.activity]\" aria-hidden=\"true\" />\n {{ PRESENCE_ACTIVITY_LABELS[person.activity] }}\n </span>\n </li>\n </ul>\n <p v-if=\"unlisted > 0\" class=\"mint-presence__rest\">and {{ unlisted }} more</p>\n <p class=\"mint-presence__foot\">\n <slot name=\"footer\">Editing is a hint, not a lock. You can still edit.</slot>\n </p>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Who else is on a presence topic: at most `max` avatars (editing first), then `+N`; one button opens the list of each person and activity. */\nimport { computed, useId, useTemplateRef, watch, type Component } from 'vue'\nimport { ChartColumn, Eye, FlaskConical, Pencil } from 'lucide-vue-next'\nimport Avatar from './Avatar.vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { useEventListener } from '../composables/useEventListener'\nimport type { PresenceActivity } from '../composables/usePresence'\nimport {\n PRESENCE_ACTIVITY_LABELS,\n arrangePresence,\n presenceSummary,\n type PresencePerson,\n} from '../utils/presenceAvatars'\n\ninterface Props {\n /** The people on the topic, for example `usePresence().viewers` with names. */\n people: PresencePerson[]\n /** The current user; never shown. */\n selfId?: string | null\n /** All people on the topic (`usePresence().count`), when the list is capped. */\n count?: number\n /** Accessible name of the list. */\n label?: string\n /** Most avatars before `+N`. */\n max?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n selfId: null,\n count: undefined,\n label: 'People here',\n max: 4,\n})\n\nconst ACTIVITY_ICONS: Record<PresenceActivity, Component> = {\n viewing: Eye,\n viewing_design: FlaskConical,\n viewing_results: ChartColumn,\n editing: Pencil,\n}\n\nconst arrangement = computed(() => arrangePresence(props.people, {\n selfId: props.selfId,\n count: props.count,\n max: props.max,\n}))\nconst summary = computed(() => presenceSummary(arrangement.value))\nconst unlisted = computed(() => arrangement.value.total - arrangement.value.others.length)\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst { isOpen, toggle, close } = useDropdownState({\n rootRef: root,\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\n// Escape closes the list from anywhere, but takes the focus back to the button only from within it.\nuseEventListener(() => document, 'keydown', (event) => {\n if (event.key === 'Escape') close(root.value?.contains(event.target as Node) ?? false)\n})\n// The root unmounts when nobody else is here; the list must not reopen on its own when someone comes back.\nwatch(() => arrangement.value.total, (total) => { if (total === 0) close() })\nconst panelId = `mint-presence-${useId()}`\n</script>\n\n<template>\n <div v-if=\"arrangement.total > 0\" ref=\"root\" class=\"mint-presence\">\n <button\n ref=\"trigger\"\n type=\"button\"\n class=\"mint-presence__trigger\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? panelId : undefined\"\n :aria-label=\"summary\"\n @click=\"toggle\"\n >\n <span class=\"mint-presence__stack\" aria-hidden=\"true\">\n <span\n v-for=\"person in arrangement.shown\"\n :key=\"person.id\"\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span v-if=\"arrangement.overflow > 0\" class=\"mint-presence__more\">+{{ arrangement.overflow }}</span>\n </span>\n </button>\n\n <div v-if=\"isOpen\" :id=\"panelId\" class=\"mint-popover mint-presence__panel\">\n <div class=\"mint-presence__head\">Here now <span class=\"mint-presence__count\">{{ arrangement.total }}</span></div>\n <ul class=\"mint-presence__list\" :aria-label=\"label\">\n <li v-for=\"person in arrangement.others\" :key=\"person.id\" class=\"mint-presence__row\">\n <span\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n aria-hidden=\"true\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span class=\"mint-presence__name\">{{ person.name }}</span>\n <span :class=\"['mint-presence__activity', { 'mint-presence__activity--editing': person.activity === 'editing' }]\">\n <component :is=\"ACTIVITY_ICONS[person.activity]\" aria-hidden=\"true\" />\n {{ PRESENCE_ACTIVITY_LABELS[person.activity] }}\n </span>\n </li>\n </ul>\n <p v-if=\"unlisted > 0\" class=\"mint-presence__rest\">and {{ unlisted }} more</p>\n <p class=\"mint-presence__foot\">\n <slot name=\"footer\">Editing is a hint, not a lock. You can still edit.</slot>\n </p>\n </div>\n </div>\n</template>\n","// Generated-UI runtime components (`@morscherlab/mint-sdk/runtime`).\n\n// Layout components\nexport { default as GeneratedPluginView } from './components/GeneratedPluginView.vue'\nexport { default as GeneratedResultRenderer } from './components/GeneratedResultRenderer.vue'\nexport { default as GeneratedPlotlyResult } from './components/GeneratedPlotlyResult.vue'\nexport { default as ComponentBindingRenderer } from './components/ComponentBindingRenderer.vue'\n/** Modal picker over the read-only server mounts, recording paths rather than copying data. */\nexport { default as GeneratedPathInput } from './components/GeneratedPathInput.vue'\n\n// Feedback components\nexport { default as RuntimeUpdateNotice } from './components/RuntimeUpdateNotice.vue'\n\n// The realtime event stream (`GET /api/events`, behind the `realtime` feature flag).\nexport {\n useRealtime,\n type RealtimeEvent,\n type RealtimeHandler,\n type UseRealtimeReturn,\n} from './composables/useRealtime'\nexport {\n usePresence,\n type PresenceActivity,\n type PresenceViewer,\n type UsePresenceReturn,\n} from './composables/usePresence'\n/** Avatar stack of the other people on a presence topic, with a list of each person and activity. */\nexport { default as PresenceAvatars } from './components/PresenceAvatars.vue'\nexport type { PresencePerson } from './utils/presenceAvatars'\n\n// HTTP client and plugin endpoint helpers. Generated clients (`@/generated/mint-plugin`)\n// build on these; plugin code uses the generated `useClient`, `useSettings` and `useJobs`.\nexport {\n AuthenticationRequiredError,\n useApi,\n type ApiClientOptions,\n type UseApiReturn,\n} from './composables/useApi'\nexport {\n buildEndpointUrl,\n createClient,\n downloadEndpoint,\n pluginFormDataFromPayload,\n resolvePluginBaseUrl,\n uploadEndpoint,\n useEventStream,\n useSettingsEndpoint,\n type BuildEndpointUrlOptions,\n type CreateClientOptions,\n type DownloadEndpointOptions,\n type EventStreamMessage,\n type PluginClientRequestOptions,\n type PluginContract,\n type PluginContractSettings,\n type PluginEndpointContract,\n type PluginEndpointDefinition,\n type PluginEndpointRequestOptions,\n type PluginFormDataPayload,\n type PluginFormDataValue,\n type PluginHttpMethod,\n type PluginNavItemContract,\n type StreamOptions,\n type UseEventStreamReturn,\n type UseSettingsEndpointOptions,\n type UseSettingsEndpointReturn,\n} from './composables/createClient'\nexport {\n createGeneratedAnalysisTransport,\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n type PluginJobRequestOptions,\n type PluginJobWaitOptions,\n type UseJobsEndpointOptions,\n type UseJobsEndpointReturn,\n} from './composables/useJobsEndpoint'\nexport {\n combinePluginJobSources,\n useJobCenter,\n type CombinedPluginJobCenterSource,\n type JobsStatusTrayTab,\n type PluginJobCenterSource,\n type UseJobCenterOptions,\n type UseJobCenterReturn,\n} from './composables/useJobCenter'\nexport { controlsTo, type ControlsTarget } from './composables/controlSchemaAdapters'\nexport { controlBindings } from './composables/controlComponentBindings'\n\n// Forms, control schemas, job helpers and platform context helpers\nexport {\n useForm,\n type ValidationRule,\n type FieldRules,\n type FieldState,\n type UseFormReturn,\n} from './composables/useForm'\nexport {\n useFormBuilder,\n evaluateCondition,\n} from './composables/useFormBuilder'\nexport {\n getFieldRegistryEntry,\n getTypeDefault,\n type RegistryEntry,\n} from './composables/formBuilderRegistry'\nexport {\n defineControlComponentBindings,\n defineControls,\n getDefaultControlView,\n getControlDefaults,\n useControlSchema,\n useControlWorkspace,\n type ControlFormSchema,\n type ControlFormBinding,\n type ControlSettingsBinding,\n type ControlSidebarBinding,\n type ControlTopBarSettingsBinding,\n type ControlValues,\n type UseControlSchemaReturn,\n type ControlWorkspaceAppTopBarPillBinding,\n type ControlWorkspaceComponentBindings,\n type ControlWorkspaceFormBinding,\n type ControlWorkspacePillNavBinding,\n type ControlWorkspaceSidebarBinding,\n type ControlWorkspaceTopBarBinding,\n type ControlWorkspaceTopBarSettingsBinding,\n type UseControlWorkspaceReturn,\n} from './composables/useControlSchema'\nexport {\n resolveCurrentPluginId,\n} from './composables/platformContextHelpers'\nexport {\n resolveJobCapabilities,\n normalizeJobPercent,\n normalizeJobState,\n isActiveJobStatus,\n isTerminalJobStatus,\n jobStatusLabel,\n type JobCapabilityInput,\n type JobCapabilities,\n} from './jobs'\nexport {\n generatedJobFormSchema,\n generatedJobDefaults,\n normalizeGeneratedJobInput,\n} from './generated/schema'\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDropdownState-8yWMu-7_.js","names":["$slots"],"sources":["../src/components/BaseButton.vue","../src/components/BaseButton.vue","../src/composables/useEventListener.ts","../src/composables/useFocusTrap.ts","../src/components/BaseModal.vue","../src/components/BaseModal.vue","../src/composables/useDropdownState.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a styled `<button>` with variant, size, loading spinner, and full-width options.\n * With `icon` and no default slot it is a square icon-only button; `label` is then its accessible name.\n *\n * @example\n * ```vue\n * <BaseButton variant=\"primary\" :loading=\"busy\">Save</BaseButton>\n * <BaseButton :icon=\"Plus\">Add sample</BaseButton>\n * <BaseButton variant=\"ghost\" :icon=\"Trash2\" label=\"Delete\" />\n * ```\n */\nimport { computed, useSlots, type Component } from 'vue'\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n /** Icon component (for example a lucide icon) rendered before the label, or alone when there is no default slot. */\n icon?: Component\n /** Accessible name and tooltip of an icon-only button. */\n label?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n icon: undefined,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst slots = useSlots()\nconst iconOnly = computed(() => Boolean(props.icon) && !slots.default)\nconst block = computed(() => (iconOnly.value ? 'mint-icon-button' : 'mint-button'))\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :aria-label=\"iconOnly ? label : undefined\"\n :title=\"iconOnly ? label : undefined\"\n :class=\"[\n block,\n `${block}--${variant}`,\n `${block}--${size}`,\n fullWidth && !iconOnly ? 'mint-button--full-width' : '',\n (disabled || loading) ? `${block}--disabled` : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n :class=\"iconOnly ? ['mint-icon-button__spinner', `mint-icon-button__icon--${size}`] : 'mint-button__spinner'\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <span v-if=\"iconOnly && !loading\" :class=\"`mint-icon-button__icon--${size}`\">\n <component :is=\"icon\" aria-hidden=\"true\" />\n </span>\n <template v-if=\"!iconOnly\">\n <component :is=\"icon\" v-if=\"icon\" class=\"mint-button__icon\" aria-hidden=\"true\" />\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </template>\n </button>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled `<button>` with variant, size, loading spinner, and full-width options.\n * With `icon` and no default slot it is a square icon-only button; `label` is then its accessible name.\n *\n * @example\n * ```vue\n * <BaseButton variant=\"primary\" :loading=\"busy\">Save</BaseButton>\n * <BaseButton :icon=\"Plus\">Add sample</BaseButton>\n * <BaseButton variant=\"ghost\" :icon=\"Trash2\" label=\"Delete\" />\n * ```\n */\nimport { computed, useSlots, type Component } from 'vue'\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n /** Icon component (for example a lucide icon) rendered before the label, or alone when there is no default slot. */\n icon?: Component\n /** Accessible name and tooltip of an icon-only button. */\n label?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n icon: undefined,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst slots = useSlots()\nconst iconOnly = computed(() => Boolean(props.icon) && !slots.default)\nconst block = computed(() => (iconOnly.value ? 'mint-icon-button' : 'mint-button'))\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :aria-label=\"iconOnly ? label : undefined\"\n :title=\"iconOnly ? label : undefined\"\n :class=\"[\n block,\n `${block}--${variant}`,\n `${block}--${size}`,\n fullWidth && !iconOnly ? 'mint-button--full-width' : '',\n (disabled || loading) ? `${block}--disabled` : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n :class=\"iconOnly ? ['mint-icon-button__spinner', `mint-icon-button__icon--${size}`] : 'mint-button__spinner'\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <span v-if=\"iconOnly && !loading\" :class=\"`mint-icon-button__icon--${size}`\">\n <component :is=\"icon\" aria-hidden=\"true\" />\n </span>\n <template v-if=\"!iconOnly\">\n <component :is=\"icon\" v-if=\"icon\" class=\"mint-button__icon\" aria-hidden=\"true\" />\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </template>\n </button>\n</template>\n","import { isRef, onMounted, onUnmounted, watch, type Ref } from 'vue'\n\nexport type EventTargetGetter<TTarget extends EventTarget = EventTarget> =\n () => TTarget | null | undefined\n\nexport type EventTargetLike<TTarget extends EventTarget = EventTarget> =\n | TTarget\n | Ref<TTarget | null | undefined>\n | EventTargetGetter<TTarget>\n | null\n | undefined\n\nexport type EventListenerEnabled = boolean | Ref<boolean>\n\nexport interface UseEventListenerObjectOptions extends AddEventListenerOptions {\n enabled?: EventListenerEnabled\n}\n\nexport type UseEventListenerOptions = boolean | UseEventListenerObjectOptions\nexport type EventListenerStop = () => void\n\nexport type EventMapFor<TTarget extends EventTarget> =\n TTarget extends Window\n ? WindowEventMap\n : TTarget extends Document\n ? DocumentEventMap\n : TTarget extends HTMLElement\n ? HTMLElementEventMap\n : Record<string, Event>\n\nexport type EventFor<\n TTarget extends EventTarget,\n TType extends string,\n> = TType extends keyof EventMapFor<TTarget>\n ? EventMapFor<TTarget>[TType]\n : Event\n\n/** Bind a DOM event listener on mount, remove it on unmount, and rebind when a ref target changes. */\nexport function useEventListener<\n TTarget extends EventTarget = EventTarget,\n TType extends string = string,\n>(\n target: EventTargetLike<TTarget>,\n type: TType,\n listener: (event: EventFor<TTarget, TType>) => void,\n options?: UseEventListenerOptions,\n): EventListenerStop {\n let stopCurrent: EventListenerStop | undefined\n let mounted = false\n\n function stop(): void {\n stopCurrent?.()\n stopCurrent = undefined\n }\n\n function start(): void {\n stop()\n if (!mounted || !isEnabled(options)) return\n const resolvedTarget = resolveEventTarget(target)\n if (!resolvedTarget) return\n\n const eventListener = listener as EventListener\n const eventOptions = getEventOptions(options)\n resolvedTarget.addEventListener(type, eventListener, eventOptions)\n stopCurrent = () => {\n resolvedTarget.removeEventListener(type, eventListener, eventOptions)\n }\n }\n\n onMounted(() => {\n mounted = true\n start()\n })\n\n if (isRef(target)) {\n watch(target, start, { flush: 'post' })\n }\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) {\n watch(enabled, start, { flush: 'post' })\n }\n\n onUnmounted(() => {\n mounted = false\n stop()\n })\n\n return stop\n}\n\nfunction resolveEventTarget(target: EventTargetLike): EventTarget | null | undefined {\n if (isRef(target)) return target.value\n if (typeof target === 'function') return target()\n return target\n}\n\nfunction getEnabledOption(options: UseEventListenerOptions | undefined): EventListenerEnabled | undefined {\n return typeof options === 'object' ? options.enabled : undefined\n}\n\nfunction isEnabled(options: UseEventListenerOptions | undefined): boolean {\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) return enabled.value\n return enabled ?? true\n}\n\nfunction getEventOptions(options: UseEventListenerOptions | undefined): boolean | AddEventListenerOptions | undefined {\n if (typeof options !== 'object') return options\n const { enabled: _enabled, ...eventOptions } = options\n return eventOptions\n}\n","import { nextTick, watch, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseFocusTrapOptions {\n /** Ref to the trap's container element. Focusable elements are queried within it. */\n containerRef: Ref<HTMLElement | null>\n /** Reactive flag — the trap activates when this becomes `true` and releases when it becomes `false`. */\n active: Ref<boolean>\n /** Restore focus to the element that was focused before activation, when the trap releases. Default `true`. */\n restoreFocus?: boolean\n}\n\nexport interface UseFocusTrapReturn {\n /** Focusable descendants of the container, in DOM order, excluding roving-tabindex (`tabindex=\"-1\"`) elements. */\n getFocusableElements: () => HTMLElement[]\n}\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\n/**\n * Traps Tab focus within a container while `active` is true: Tab wraps from the last\n * focusable element back to the first (and Shift+Tab from the first to the last), the\n * first focusable element (or the container itself, if none) receives focus when the\n * trap activates, an `[autofocus]` descendant taking precedence, and focus returns to\n * whatever was focused beforehand when it releases.\n * Used by BaseModal and WellEditPopupInternal.\n */\nexport function useFocusTrap(options: UseFocusTrapOptions): UseFocusTrapReturn {\n const { containerRef, active } = options\n const restoreFocus = options.restoreFocus ?? true\n let previouslyFocused: HTMLElement | null = null\n\n function getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n // Roving tabindex (inactive tabs/rail items) stays out of the Tab cycle. Checking\n // the attribute directly (rather than the `.tabIndex` IDL property) avoids relying\n // on a browser/engine's default-tabindex computation for freshly-patched elements.\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n .filter((el) => el.getAttribute('tabindex') !== '-1')\n }\n\n function handleKeydown(event: KeyboardEvent) {\n if (event.key !== 'Tab' || !active.value || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n }\n\n // `immediate` so a container mounted already active (`v-if` + a constant\n // `modelValue`) still takes focus. `flush: 'sync'` so releasing the trap from `onBeforeUnmount` restores focus\n // before the component's reactive scope is torn down — a batched (default\n // 'pre') watcher would be scheduled but never flushed once that scope stops.\n watch(active, async (isActive) => {\n if (isActive) {\n previouslyFocused = document.activeElement as HTMLElement | null\n await nextTick()\n // Like <dialog>: an [autofocus] descendant wins over the first focusable element.\n const target = containerRef.value?.querySelector<HTMLElement>('[autofocus]') ?? getFocusableElements()[0]\n if (target) {\n target.focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n if (restoreFocus) previouslyFocused?.focus()\n previouslyFocused = null\n }\n }, { flush: 'sync', immediate: true })\n\n useEventListener(() => document, 'keydown', handleKeydown)\n\n return { getFocusableElements }\n}\n","<script lang=\"ts\">\n/** Open modals, oldest first; shared by every BaseModal instance. */\nconst openModals: object[] = []\n</script>\n\n<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, toRef, watch, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\nimport { useFocusTrap } from '../composables/useFocusTrap'\n\nexport interface Props {\n open: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\n/** Roving tabindex; with no active tab (e.g. a search is showing) the first tab stays reachable. */\nfunction isTabStop(tab: ModalTab, index: number): boolean {\n return activeTabMeta.value ? tab.id === props.activeTab : index === 0\n}\n\n/** A rail section heading goes before the first tab of each run of one `section`. */\nfunction startsSection(index: number): boolean {\n const section = props.tabs[index].section\n return !!section && section !== props.tabs[index - 1]?.section\n}\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\n\nuseFocusTrap({ containerRef, active: toRef(props, 'open') })\n\nwatch(() => props.open, (isOpen) => {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n})\n\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n}, { immediate: true })\n\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.open && openModals[openModals.length - 1] === self) {\n close()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:open', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nuseEventListener(() => document, 'keydown', handleEscapeKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"open\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"(tab, index) in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <template v-for=\"(tab, index) in tabs\" :key=\"tab.id\">\n <template v-if=\"startsSection(index)\">\n <div v-if=\"index > 0\" class=\"mint-modal__rail-divider\" aria-hidden=\"true\" />\n <span class=\"mint-modal__rail-section\" aria-hidden=\"true\">{{ tab.section }}</span>\n </template>\n <button\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </template>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"$slots['pane-header'] || activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <!-- Replaces the default title + subtitle, e.g. to add pane actions. -->\n <slot name=\"pane-header\" :tab=\"activeTabMeta\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta?.label }}</h4>\n <p v-if=\"activeTabMeta?.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </slot>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n","<script lang=\"ts\">\n/** Open modals, oldest first; shared by every BaseModal instance. */\nconst openModals: object[] = []\n</script>\n\n<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, toRef, watch, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\nimport { useFocusTrap } from '../composables/useFocusTrap'\n\nexport interface Props {\n open: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\n/** Roving tabindex; with no active tab (e.g. a search is showing) the first tab stays reachable. */\nfunction isTabStop(tab: ModalTab, index: number): boolean {\n return activeTabMeta.value ? tab.id === props.activeTab : index === 0\n}\n\n/** A rail section heading goes before the first tab of each run of one `section`. */\nfunction startsSection(index: number): boolean {\n const section = props.tabs[index].section\n return !!section && section !== props.tabs[index - 1]?.section\n}\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\n\nuseFocusTrap({ containerRef, active: toRef(props, 'open') })\n\nwatch(() => props.open, (isOpen) => {\n document.body.style.overflow = isOpen ? 'hidden' : ''\n})\n\n// Every open modal listens on document, so only the most recently opened one answers Escape.\nconst self = {}\nwatch(() => props.open, (isOpen) => {\n const index = openModals.indexOf(self)\n if (isOpen && index === -1) openModals.push(self)\n if (!isOpen && index !== -1) openModals.splice(index, 1)\n}, { immediate: true })\n\nfunction handleEscapeKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.open && openModals[openModals.length - 1] === self) {\n close()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:open', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nuseEventListener(() => document, 'keydown', handleEscapeKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n const index = openModals.indexOf(self)\n if (index !== -1) openModals.splice(index, 1)\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"open\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"(tab, index) in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <template v-for=\"(tab, index) in tabs\" :key=\"tab.id\">\n <template v-if=\"startsSection(index)\">\n <div v-if=\"index > 0\" class=\"mint-modal__rail-divider\" aria-hidden=\"true\" />\n <span class=\"mint-modal__rail-section\" aria-hidden=\"true\">{{ tab.section }}</span>\n </template>\n <button\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"isTabStop(tab, index) ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </template>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"$slots['pane-header'] || activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <!-- Replaces the default title + subtitle, e.g. to add pane actions. -->\n <slot name=\"pane-header\" :tab=\"activeTabMeta\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta?.label }}</h4>\n <p v-if=\"activeTabMeta?.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </slot>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n","import { nextTick, ref, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseDropdownStateOptions {\n closeOnOutsideClick?: boolean\n closeOnEscape?: boolean\n /** Close the panel when the page scrolls or the viewport resizes. Default `false`. */\n closeOnScroll?: boolean\n insideRefs?: Array<Ref<HTMLElement | null>>\n /**\n * Element that counts as \"inside\" for outside-click closing, typically a\n * `useTemplateRef()`. Without one, bind the returned `rootRef` instead.\n */\n rootRef?: Ref<HTMLElement | null>\n /**\n * Element focus returns to when the panel closes with `close(true)` (Escape).\n * Pass one when the trigger lives outside `rootRef`; otherwise bind the\n * returned `triggerRef` to the trigger element.\n */\n triggerRef?: Ref<HTMLElement | null>\n onOpen?: () => void\n onClose?: () => void\n}\n\nexport interface UseDropdownStateReturn {\n isOpen: Ref<boolean>\n rootRef: Ref<HTMLElement | null>\n /** Bind to the trigger element so Escape can return focus to it. */\n triggerRef: Ref<HTMLElement | null>\n open: () => void\n /** Closes the panel; `returnFocus` moves focus back to `triggerRef`. */\n close: (returnFocus?: boolean) => void\n toggle: () => void\n handleClickOutside: (event: MouseEvent) => void\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * Shared disclosure state for dropdown-style SDK components: open/close state,\n * outside-click and Escape closing, optional scroll/resize closing, and focus\n * return to the trigger. `close(returnFocus)` mirrors `useMenuKeyboard`'s\n * contract, so the two compose directly.\n */\nexport function useDropdownState(options: UseDropdownStateOptions = {}): UseDropdownStateReturn {\n const isOpen = ref(false)\n const rootRef = options.rootRef ?? ref<HTMLElement | null>(null)\n const triggerRef = options.triggerRef ?? ref<HTMLElement | null>(null)\n const closeOnOutsideClick = options.closeOnOutsideClick ?? true\n const closeOnEscape = options.closeOnEscape ?? true\n const closeOnScroll = options.closeOnScroll ?? false\n\n function open(): void {\n if (isOpen.value) return\n isOpen.value = true\n options.onOpen?.()\n }\n\n function close(returnFocus = false): void {\n if (!isOpen.value) return\n isOpen.value = false\n options.onClose?.()\n if (returnFocus) {\n void nextTick(() => triggerRef.value?.focus())\n }\n }\n\n function toggle(): void {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n function handleClickOutside(event: MouseEvent): void {\n if (!closeOnOutsideClick || !isOpen.value || !rootRef.value) return\n const target = event.target\n if (\n target instanceof Node &&\n !rootRef.value.contains(target) &&\n !options.insideRefs?.some(ref => ref.value?.contains(target))\n ) {\n close()\n }\n }\n\n function handleKeydown(event: KeyboardEvent): void {\n if (closeOnEscape && event.key === 'Escape') {\n close(true)\n }\n }\n\n function handleViewportChange(): void {\n if (isOpen.value) close()\n }\n\n if (closeOnOutsideClick) {\n useEventListener(() => document, 'click', handleClickOutside)\n }\n if (closeOnEscape) {\n useEventListener(() => document, 'keydown', handleKeydown)\n }\n if (closeOnScroll) {\n useEventListener(() => window, 'scroll', handleViewportChange, true)\n useEventListener(() => window, 'resize', handleViewportChange)\n }\n\n return {\n isOpen,\n rootRef,\n triggerRef,\n open,\n close,\n toggle,\n handleClickOutside,\n handleKeydown,\n }\n}\n"],"mappings":"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"}