@morscherlab/mint-sdk 1.0.0-beta.2 → 1.0.0-beta.3

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 (399) hide show
  1. package/README.md +218 -6
  2. package/dist/__tests__/components/ActionItem.test.d.ts +1 -0
  3. package/dist/__tests__/components/AppAvatarMenu.test.d.ts +1 -0
  4. package/dist/__tests__/components/AppPageSelector.test.d.ts +1 -0
  5. package/dist/__tests__/components/AppPillNav.test.d.ts +1 -0
  6. package/dist/__tests__/components/AppPluginSwitcher.test.d.ts +1 -0
  7. package/dist/__tests__/components/AppToastContainer.test.d.ts +1 -0
  8. package/dist/__tests__/components/BaseRadioGroup.test.d.ts +1 -0
  9. package/dist/__tests__/components/BaseSelect.test.d.ts +1 -0
  10. package/dist/__tests__/components/BaseTabs.test.d.ts +1 -0
  11. package/dist/__tests__/components/BatchProgressList.test.d.ts +1 -0
  12. package/dist/__tests__/components/BioTemplateExperimentWorkspaceView.test.d.ts +1 -0
  13. package/dist/__tests__/components/BioTemplatePackWorkspaceView.test.d.ts +1 -0
  14. package/dist/__tests__/components/BioTemplatePresetWorkspaceView.test.d.ts +1 -0
  15. package/dist/__tests__/components/BioTemplateRenderer.test.d.ts +1 -0
  16. package/dist/__tests__/components/Breadcrumb.test.d.ts +1 -0
  17. package/dist/__tests__/components/CalendarGridPanel.test.d.ts +1 -0
  18. package/dist/__tests__/components/ConcentrationInput.test.d.ts +1 -0
  19. package/dist/__tests__/components/ControlWorkspaceView.test.d.ts +1 -0
  20. package/dist/__tests__/components/DatePicker.test.d.ts +1 -0
  21. package/dist/__tests__/components/DateTimePicker.test.d.ts +1 -0
  22. package/dist/__tests__/components/EmptyState.test.d.ts +1 -0
  23. package/dist/__tests__/components/ExperimentPopover.test.d.ts +1 -0
  24. package/dist/__tests__/components/FormBuilder.test.d.ts +1 -0
  25. package/dist/__tests__/components/FormCompatibility.test.d.ts +1 -0
  26. package/dist/__tests__/components/GroupAssigner.test.d.ts +1 -0
  27. package/dist/__tests__/components/GroupingModal.test.d.ts +1 -0
  28. package/dist/__tests__/components/MultiSelect.test.d.ts +1 -0
  29. package/dist/__tests__/components/ProtocolStepEditor.test.d.ts +1 -0
  30. package/dist/__tests__/components/ReagentList.test.d.ts +1 -0
  31. package/dist/__tests__/components/SampleHierarchyTree.test.d.ts +1 -0
  32. package/dist/__tests__/components/SampleSelector.test.d.ts +1 -0
  33. package/dist/__tests__/components/SegmentedControl.test.d.ts +1 -0
  34. package/dist/__tests__/components/SettingsButton.test.d.ts +1 -0
  35. package/dist/__tests__/components/SettingsModal.test.d.ts +1 -0
  36. package/dist/__tests__/components/TagsInput.test.d.ts +1 -0
  37. package/dist/__tests__/components/ThemeToggle.test.d.ts +1 -0
  38. package/dist/__tests__/components/TimePicker.test.d.ts +1 -0
  39. package/dist/__tests__/composables/useBioTemplatePackWorkspace.test.d.ts +1 -0
  40. package/dist/__tests__/composables/useBioTemplatePresetWorkspace.test.d.ts +1 -0
  41. package/dist/__tests__/composables/useBioTemplateWorkspace.test.d.ts +1 -0
  42. package/dist/__tests__/composables/useCalendarGrid.test.d.ts +1 -0
  43. package/dist/__tests__/composables/useControlSchema.test.d.ts +1 -0
  44. package/dist/__tests__/composables/useDebouncedWatch.test.d.ts +1 -0
  45. package/dist/__tests__/composables/useDropdownState.test.d.ts +1 -0
  46. package/dist/__tests__/composables/useEventListener.test.d.ts +1 -0
  47. package/dist/__tests__/composables/useExpansionSet.test.d.ts +1 -0
  48. package/dist/__tests__/composables/useExperimentData.test.d.ts +1 -0
  49. package/dist/__tests__/composables/useExperimentSelector.test.d.ts +1 -0
  50. package/dist/__tests__/composables/useGroupAssignment.test.d.ts +1 -0
  51. package/dist/__tests__/composables/useListSelection.test.d.ts +1 -0
  52. package/dist/__tests__/composables/usePluginClient.test.d.ts +1 -0
  53. package/dist/__tests__/composables/usePluginConfig.test.d.ts +1 -0
  54. package/dist/__tests__/composables/useRequestSyncState.test.d.ts +1 -0
  55. package/dist/__tests__/composables/useSampleGroups.test.d.ts +1 -0
  56. package/dist/__tests__/composables/useSelectionLimit.test.d.ts +1 -0
  57. package/dist/__tests__/composables/useSortedItems.test.d.ts +1 -0
  58. package/dist/__tests__/composables/useTemplateCollection.test.d.ts +1 -0
  59. package/dist/__tests__/composables/useTextSearch.test.d.ts +1 -0
  60. package/dist/__tests__/composables/useTheme.test.d.ts +1 -0
  61. package/dist/__tests__/composables/useTimeUtils.test.d.ts +1 -0
  62. package/dist/__tests__/docs/frontendDocsCatalog.test.d.ts +1 -0
  63. package/dist/__tests__/templates/templates.test.d.ts +1 -0
  64. package/dist/{auth-DsI0rQ7_.js → auth-QQj2kkze.js} +12 -5
  65. package/dist/auth-QQj2kkze.js.map +1 -0
  66. package/dist/components/ActionItem.vue.d.ts +32 -0
  67. package/dist/components/AppAvatarMenu.vue.d.ts +2 -7
  68. package/dist/components/AppPageSelector.vue.d.ts +3 -6
  69. package/dist/components/AppPillNav.vue.d.ts +2 -2
  70. package/dist/components/AppSidebar.vue.d.ts +56 -3
  71. package/dist/components/AppToastContainer.vue.d.ts +2 -0
  72. package/dist/components/AppTopBar.vue.d.ts +41 -10
  73. package/dist/components/BaseButton.vue.d.ts +1 -1
  74. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  75. package/dist/components/BaseInput.vue.d.ts +2 -2
  76. package/dist/components/BasePill.vue.d.ts +2 -2
  77. package/dist/components/BaseRadioGroup.vue.d.ts +3 -3
  78. package/dist/components/BaseSelect.vue.d.ts +3 -3
  79. package/dist/components/BaseTabs.vue.d.ts +2 -2
  80. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  81. package/dist/components/BaseToggle.vue.d.ts +1 -1
  82. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +117 -0
  83. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +92 -0
  84. package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +82 -0
  85. package/dist/components/BioTemplateRenderer.vue.d.ts +29 -0
  86. package/dist/components/Breadcrumb.vue.d.ts +2 -2
  87. package/dist/components/Calendar.vue.d.ts +1 -1
  88. package/dist/components/CalendarGridPanel.vue.d.ts +25 -0
  89. package/dist/components/CollapsibleCard.vue.d.ts +1 -1
  90. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  91. package/dist/components/ConfirmDialog.vue.d.ts +2 -2
  92. package/dist/components/ControlWorkspaceView.vue.d.ts +130 -0
  93. package/dist/components/DatePicker.vue.d.ts +1 -1
  94. package/dist/components/DateTimePicker.vue.d.ts +3 -3
  95. package/dist/components/Divider.vue.d.ts +1 -1
  96. package/dist/components/DropdownButton.vue.d.ts +3 -3
  97. package/dist/components/EmptyState.vue.d.ts +1 -2
  98. package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
  99. package/dist/components/ExperimentTimeline.vue.d.ts +2 -2
  100. package/dist/components/FileUploader.vue.d.ts +1 -1
  101. package/dist/components/FitPanel.vue.d.ts +1 -1
  102. package/dist/components/FormActions.vue.d.ts +4 -4
  103. package/dist/components/FormBuilder.vue.d.ts +22 -8
  104. package/dist/components/FormFieldRenderer.vue.d.ts +7 -10
  105. package/dist/components/FormSection.vue.d.ts +11 -24
  106. package/dist/components/FormulaInput.vue.d.ts +2 -2
  107. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  108. package/dist/components/MultiSelect.vue.d.ts +3 -3
  109. package/dist/components/NumberInput.vue.d.ts +1 -1
  110. package/dist/components/ProgressBar.vue.d.ts +1 -1
  111. package/dist/components/ProtocolStepEditor.vue.d.ts +3 -1
  112. package/dist/components/RackEditor.vue.d.ts +2 -2
  113. package/dist/components/SampleLegend.vue.d.ts +2 -2
  114. package/dist/components/ScheduleCalendar.vue.d.ts +2 -2
  115. package/dist/components/SegmentedControl.vue.d.ts +2 -2
  116. package/dist/components/SequenceInput.vue.d.ts +3 -3
  117. package/dist/components/SettingsButton.vue.d.ts +2 -2
  118. package/dist/components/SettingsModal.vue.d.ts +13 -5
  119. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  120. package/dist/components/TagsInput.vue.d.ts +3 -2
  121. package/dist/components/TimePicker.vue.d.ts +3 -3
  122. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  123. package/dist/components/UnitInput.vue.d.ts +2 -2
  124. package/dist/components/WellPlate.vue.d.ts +8 -8
  125. package/dist/components/index.d.ts +11 -1
  126. package/dist/components/index.js +3 -3
  127. package/dist/components/internal/FormFieldRendererInternal.vue.d.ts +31 -0
  128. package/dist/components/internal/FormSectionRenderer.vue.d.ts +43 -0
  129. package/dist/{components-_XqPEhP9.js → components-D_Sr0adg.js} +7290 -6518
  130. package/dist/components-D_Sr0adg.js.map +1 -0
  131. package/dist/composables/index.d.ts +21 -2
  132. package/dist/composables/index.js +4 -3
  133. package/dist/composables/platformContextHelpers.d.ts +14 -0
  134. package/dist/composables/useBioTemplateComponents.d.ts +20 -0
  135. package/dist/composables/useBioTemplateControls.d.ts +6 -0
  136. package/dist/composables/useBioTemplatePackWorkspace.d.ts +45 -0
  137. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +74 -0
  138. package/dist/composables/useBioTemplateWorkspace.d.ts +50 -0
  139. package/dist/composables/useCalendarGrid.d.ts +26 -0
  140. package/dist/composables/useControlSchema.d.ts +321 -0
  141. package/dist/composables/useDebouncedWatch.d.ts +20 -0
  142. package/dist/composables/useDropdownState.d.ts +19 -0
  143. package/dist/composables/useEventListener.d.ts +13 -0
  144. package/dist/composables/useExpansionSet.d.ts +21 -0
  145. package/dist/composables/useExperimentData.d.ts +10 -0
  146. package/dist/composables/useExperimentSave.d.ts +31 -2
  147. package/dist/composables/useExperimentSelector.d.ts +20 -0
  148. package/dist/composables/useForm.d.ts +2 -0
  149. package/dist/composables/useGroupAssignment.d.ts +31 -0
  150. package/dist/composables/useListSelection.d.ts +35 -0
  151. package/dist/composables/usePlatformContext.d.ts +21 -3
  152. package/dist/composables/usePluginApi.d.ts +7 -14
  153. package/dist/composables/usePluginClient.d.ts +109 -0
  154. package/dist/composables/usePluginConfig.d.ts +12 -0
  155. package/dist/composables/useRequestSyncState.d.ts +34 -0
  156. package/dist/composables/useSampleGroups.d.ts +32 -0
  157. package/dist/composables/useSelectionLimit.d.ts +17 -0
  158. package/dist/composables/useSortedItems.d.ts +32 -0
  159. package/dist/composables/useTemplateCollection.d.ts +58 -0
  160. package/dist/composables/useTextSearch.d.ts +18 -0
  161. package/dist/composables/useTimeUtils.d.ts +8 -0
  162. package/dist/{composables-tiZqLu1M.js → composables-C3dpXQN5.js} +228 -146
  163. package/dist/composables-C3dpXQN5.js.map +1 -0
  164. package/dist/index.d.ts +12 -3
  165. package/dist/index.js +6 -5
  166. package/dist/install.d.ts +7 -2
  167. package/dist/install.js +2 -2
  168. package/dist/install.js.map +1 -1
  169. package/dist/stores/index.js +1 -1
  170. package/dist/stores/settings.d.ts +4 -1
  171. package/dist/styles.css +5235 -5977
  172. package/dist/templates/adapters.d.ts +43 -0
  173. package/dist/templates/builders.d.ts +63 -0
  174. package/dist/templates/catalog.d.ts +188 -0
  175. package/dist/templates/componentBindings.d.ts +58 -0
  176. package/dist/templates/controlSchemas.d.ts +25 -0
  177. package/dist/templates/index.d.ts +15 -0
  178. package/dist/templates/index.js +2 -0
  179. package/dist/templates/lookup.d.ts +4 -0
  180. package/dist/templates/packs.d.ts +18 -0
  181. package/dist/templates/presets.d.ts +90 -0
  182. package/dist/templates/types.d.ts +531 -0
  183. package/dist/templates-50NPjaxL.js +9333 -0
  184. package/dist/templates-50NPjaxL.js.map +1 -0
  185. package/dist/types/components.d.ts +26 -4
  186. package/dist/types/form-builder.d.ts +6 -8
  187. package/dist/types/index.d.ts +2 -2
  188. package/dist/types/platform.d.ts +7 -1
  189. package/dist/useScheduleDrag-D4oWdh41.js +4371 -0
  190. package/dist/useScheduleDrag-D4oWdh41.js.map +1 -0
  191. package/dist/utils/formModelSync.d.ts +5 -0
  192. package/dist/utils/items.d.ts +8 -0
  193. package/dist/utils/options.d.ts +6 -0
  194. package/dist/utils/pluginIcon.d.ts +9 -0
  195. package/package.json +7 -2
  196. package/src/__tests__/components/ActionItem.test.ts +99 -0
  197. package/src/__tests__/components/AppAvatarMenu.test.ts +27 -0
  198. package/src/__tests__/components/AppPageSelector.test.ts +134 -0
  199. package/src/__tests__/components/AppPillNav.test.ts +78 -0
  200. package/src/__tests__/components/AppPluginSwitcher.test.ts +44 -0
  201. package/src/__tests__/components/AppSidebar.test.ts +370 -0
  202. package/src/__tests__/components/AppToastContainer.test.ts +48 -0
  203. package/src/__tests__/components/AppTopBar.test.ts +383 -0
  204. package/src/__tests__/components/BaseRadioGroup.test.ts +25 -0
  205. package/src/__tests__/components/BaseSelect.test.ts +21 -0
  206. package/src/__tests__/components/BaseTabs.test.ts +25 -0
  207. package/src/__tests__/components/BatchProgressList.test.ts +52 -0
  208. package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +153 -0
  209. package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +161 -0
  210. package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +281 -0
  211. package/src/__tests__/components/BioTemplateRenderer.test.ts +71 -0
  212. package/src/__tests__/components/Breadcrumb.test.ts +23 -0
  213. package/src/__tests__/components/CalendarGridPanel.test.ts +36 -0
  214. package/src/__tests__/components/ConcentrationInput.test.ts +45 -0
  215. package/src/__tests__/components/ControlWorkspaceView.test.ts +1031 -0
  216. package/src/__tests__/components/DataFrame.test.ts +11 -0
  217. package/src/__tests__/components/DatePicker.test.ts +45 -0
  218. package/src/__tests__/components/DateTimePicker.test.ts +48 -0
  219. package/src/__tests__/components/DropdownButton.test.ts +23 -0
  220. package/src/__tests__/components/EmptyState.test.ts +23 -0
  221. package/src/__tests__/components/ExperimentPopover.test.ts +56 -0
  222. package/src/__tests__/components/FormBuilder.test.ts +296 -0
  223. package/src/__tests__/components/FormCompatibility.test.ts +94 -0
  224. package/src/__tests__/components/GroupAssigner.test.ts +30 -0
  225. package/src/__tests__/components/GroupingModal.test.ts +73 -0
  226. package/src/__tests__/components/MultiSelect.test.ts +48 -0
  227. package/src/__tests__/components/ProtocolStepEditor.test.ts +33 -0
  228. package/src/__tests__/components/ReagentList.test.ts +82 -0
  229. package/src/__tests__/components/SampleHierarchyTree.test.ts +53 -0
  230. package/src/__tests__/components/SampleSelector.test.ts +60 -0
  231. package/src/__tests__/components/SegmentedControl.test.ts +24 -0
  232. package/src/__tests__/components/SettingsButton.test.ts +44 -0
  233. package/src/__tests__/components/SettingsModal.test.ts +296 -0
  234. package/src/__tests__/components/TagsInput.test.ts +75 -0
  235. package/src/__tests__/components/ThemeToggle.test.ts +47 -0
  236. package/src/__tests__/components/TimePicker.test.ts +38 -0
  237. package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +122 -0
  238. package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +199 -0
  239. package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +99 -0
  240. package/src/__tests__/composables/useCalendarGrid.test.ts +38 -0
  241. package/src/__tests__/composables/useControlSchema.test.ts +919 -0
  242. package/src/__tests__/composables/useDebouncedWatch.test.ts +93 -0
  243. package/src/__tests__/composables/useDropdownState.test.ts +95 -0
  244. package/src/__tests__/composables/useEventListener.test.ts +116 -0
  245. package/src/__tests__/composables/useExpansionSet.test.ts +62 -0
  246. package/src/__tests__/composables/useExperimentData.test.ts +4 -0
  247. package/src/__tests__/composables/useExperimentSave.test.ts +203 -8
  248. package/src/__tests__/composables/useExperimentSelector.test.ts +164 -0
  249. package/src/__tests__/composables/useForm.test.ts +58 -0
  250. package/src/__tests__/composables/useFormBuilder.test.ts +77 -0
  251. package/src/__tests__/composables/useGroupAssignment.test.ts +73 -0
  252. package/src/__tests__/composables/useListSelection.test.ts +66 -0
  253. package/src/__tests__/composables/usePluginClient.test.ts +444 -0
  254. package/src/__tests__/composables/usePluginConfig.test.ts +5 -0
  255. package/src/__tests__/composables/useRequestSyncState.test.ts +92 -0
  256. package/src/__tests__/composables/useSampleGroups.test.ts +66 -0
  257. package/src/__tests__/composables/useSelectionLimit.test.ts +41 -0
  258. package/src/__tests__/composables/useSortedItems.test.ts +87 -0
  259. package/src/__tests__/composables/useTemplateCollection.test.ts +147 -0
  260. package/src/__tests__/composables/useTextSearch.test.ts +55 -0
  261. package/src/__tests__/composables/useTheme.test.ts +91 -0
  262. package/src/__tests__/composables/useTimeUtils.test.ts +35 -0
  263. package/src/__tests__/docs/frontendDocsCatalog.test.ts +229 -0
  264. package/src/__tests__/fixtures/templates/dose-response.json +81 -0
  265. package/src/__tests__/fixtures/templates/plate-map.json +54 -0
  266. package/src/__tests__/fixtures/templates/qpcr-plate.json +96 -0
  267. package/src/__tests__/fixtures/templates/sample-sheet.json +71 -0
  268. package/src/__tests__/templates/templates.test.ts +1043 -0
  269. package/src/components/ActionItem.vue +82 -0
  270. package/src/components/AppAvatarMenu.vue +15 -69
  271. package/src/components/AppLayout.story.vue +25 -25
  272. package/src/components/AppPageSelector.vue +63 -94
  273. package/src/components/AppPillNav.vue +44 -39
  274. package/src/components/AppPluginSwitcher.vue +41 -145
  275. package/src/components/AppSidebar.story.vue +94 -0
  276. package/src/components/AppSidebar.vue +187 -12
  277. package/src/components/{ToastNotification.story.vue → AppToastContainer.story.vue} +6 -6
  278. package/src/components/AppToastContainer.vue +62 -0
  279. package/src/components/AppTopBar.story.vue +7 -30
  280. package/src/components/AppTopBar.vue +251 -57
  281. package/src/components/BaseModal.vue +3 -5
  282. package/src/components/BaseRadioGroup.vue +7 -3
  283. package/src/components/BaseSelect.vue +11 -7
  284. package/src/components/BaseTabs.vue +6 -4
  285. package/src/components/BatchProgressList.vue +5 -8
  286. package/src/components/BioTemplateExperimentWorkspaceView.story.vue +123 -0
  287. package/src/components/BioTemplateExperimentWorkspaceView.vue +337 -0
  288. package/src/components/BioTemplatePackWorkspaceView.story.vue +107 -0
  289. package/src/components/BioTemplatePackWorkspaceView.vue +176 -0
  290. package/src/components/BioTemplatePresetWorkspaceView.story.vue +151 -0
  291. package/src/components/BioTemplatePresetWorkspaceView.vue +392 -0
  292. package/src/components/BioTemplateRenderer.story.vue +57 -0
  293. package/src/components/BioTemplateRenderer.vue +269 -0
  294. package/src/components/Breadcrumb.vue +14 -8
  295. package/src/components/CalendarGridPanel.vue +120 -0
  296. package/src/components/ConcentrationInput.vue +27 -64
  297. package/src/components/ControlWorkspaceView.story.vue +336 -0
  298. package/src/components/ControlWorkspaceView.vue +347 -0
  299. package/src/components/DataFrame.vue +34 -50
  300. package/src/components/DatePicker.vue +59 -192
  301. package/src/components/DateTimePicker.vue +50 -171
  302. package/src/components/DropdownButton.vue +14 -32
  303. package/src/components/EmptyState.vue +4 -2
  304. package/src/components/ExperimentPopover.vue +5 -22
  305. package/src/components/FormBuilder.vue +124 -27
  306. package/src/components/FormFieldRenderer.vue +15 -38
  307. package/src/components/FormSection.vue +20 -73
  308. package/src/components/GroupAssigner.vue +24 -56
  309. package/src/components/GroupingModal.story.vue +3 -3
  310. package/src/components/GroupingModal.vue +30 -391
  311. package/src/components/MultiSelect.vue +17 -12
  312. package/src/components/PlateMapEditor.vue +3 -8
  313. package/src/components/PluginIcon.vue +2 -22
  314. package/src/components/ProtocolStepEditor.vue +13 -22
  315. package/src/components/ReagentList.vue +25 -33
  316. package/src/components/SampleHierarchyTree.vue +12 -23
  317. package/src/components/SampleSelector.vue +42 -122
  318. package/src/components/SegmentedControl.vue +7 -3
  319. package/src/components/SettingsButton.story.vue +1 -1
  320. package/src/components/SettingsButton.vue +15 -27
  321. package/src/components/SettingsModal.story.vue +1 -1
  322. package/src/components/SettingsModal.vue +120 -29
  323. package/src/components/TagsInput.vue +29 -14
  324. package/src/components/ThemeToggle.vue +9 -7
  325. package/src/components/TimePicker.vue +19 -41
  326. package/src/components/ToastNotification.vue +4 -57
  327. package/src/components/Tooltip.vue +7 -12
  328. package/src/components/WellEditPopup.vue +3 -8
  329. package/src/components/WellPlate.vue +4 -10
  330. package/src/components/index.ts +11 -1
  331. package/src/components/internal/FormFieldRendererInternal.vue +50 -0
  332. package/src/components/internal/FormSectionRenderer.vue +78 -0
  333. package/src/composables/index.ts +212 -0
  334. package/src/composables/platformContextHelpers.ts +74 -0
  335. package/src/composables/useBioTemplateComponents.ts +93 -0
  336. package/src/composables/useBioTemplateControls.ts +41 -0
  337. package/src/composables/useBioTemplatePackWorkspace.ts +181 -0
  338. package/src/composables/useBioTemplatePresetWorkspace.ts +337 -0
  339. package/src/composables/useBioTemplateWorkspace.ts +139 -0
  340. package/src/composables/useCalendarGrid.ts +140 -0
  341. package/src/composables/useControlSchema.ts +1274 -0
  342. package/src/composables/useDebouncedWatch.ts +119 -0
  343. package/src/composables/useDropdownState.ts +83 -0
  344. package/src/composables/useEventListener.ts +111 -0
  345. package/src/composables/useExpansionSet.ts +117 -0
  346. package/src/composables/useExperimentData.ts +20 -11
  347. package/src/composables/useExperimentSave.ts +202 -50
  348. package/src/composables/useExperimentSelector.ts +86 -72
  349. package/src/composables/useForm.ts +49 -4
  350. package/src/composables/useFormBuilder.ts +93 -42
  351. package/src/composables/useGroupAssignment.ts +148 -0
  352. package/src/composables/useListSelection.ts +158 -0
  353. package/src/composables/usePluginApi.ts +7 -14
  354. package/src/composables/usePluginClient.ts +425 -0
  355. package/src/composables/usePluginConfig.ts +34 -13
  356. package/src/composables/useRequestSyncState.ts +126 -0
  357. package/src/composables/useSampleGroups.ts +126 -0
  358. package/src/composables/useSelectionLimit.ts +57 -0
  359. package/src/composables/useSortedItems.ts +118 -0
  360. package/src/composables/useTemplateCollection.ts +229 -0
  361. package/src/composables/useTextSearch.ts +60 -0
  362. package/src/composables/useTheme.ts +2 -28
  363. package/src/composables/useTimeUtils.ts +26 -2
  364. package/src/composables/useWellPlateEditor.ts +13 -9
  365. package/src/index.ts +224 -4
  366. package/src/install.ts +11 -4
  367. package/src/stores/settings.ts +13 -9
  368. package/src/styles/components/app-page-selector.css +23 -0
  369. package/src/styles/components/app-pill-nav.css +7 -0
  370. package/src/styles/components/app-top-bar.css +34 -0
  371. package/src/styles/components/concentration-input.css +3 -142
  372. package/src/styles/components/empty-state.css +0 -16
  373. package/src/styles/components/settings-button.css +3 -66
  374. package/src/styles/components/theme-toggle.css +3 -66
  375. package/src/styles/index.css +0 -1
  376. package/src/templates/adapters.ts +785 -0
  377. package/src/templates/builders.ts +2149 -0
  378. package/src/templates/catalog.ts +245 -0
  379. package/src/templates/componentBindings.ts +615 -0
  380. package/src/templates/controlSchemas.ts +718 -0
  381. package/src/templates/index.ts +314 -0
  382. package/src/templates/lookup.ts +18 -0
  383. package/src/templates/packs.ts +156 -0
  384. package/src/templates/presets.ts +146 -0
  385. package/src/templates/types.ts +668 -0
  386. package/src/types/components.ts +41 -4
  387. package/src/types/form-builder.ts +7 -2
  388. package/src/types/index.ts +14 -0
  389. package/src/types/platform.ts +7 -1
  390. package/src/utils/formModelSync.ts +52 -0
  391. package/src/utils/items.ts +28 -0
  392. package/src/utils/options.ts +23 -0
  393. package/src/utils/pluginIcon.ts +30 -0
  394. package/dist/auth-DsI0rQ7_.js.map +0 -1
  395. package/dist/components-_XqPEhP9.js.map +0 -1
  396. package/dist/composables-tiZqLu1M.js.map +0 -1
  397. package/dist/useScheduleDrag-CA9sGNJG.js +0 -7181
  398. package/dist/useScheduleDrag-CA9sGNJG.js.map +0 -1
  399. package/src/styles/components/grouping-modal.css +0 -323
@@ -2,6 +2,8 @@
2
2
  /** Sortable, searchable table of experiment reagents showing lot number, expiry, storage conditions, and stock level with low-stock warnings. */
3
3
  import { ref, computed } from 'vue'
4
4
  import type { ReagentColumn, Reagent } from '../types'
5
+ import { useSortedItems } from '../composables/useSortedItems'
6
+ import { useTextSearch } from '../composables/useTextSearch'
5
7
 
6
8
  interface Props {
7
9
  modelValue?: Reagent[]
@@ -50,43 +52,33 @@ const columnLabels: Record<ReagentColumn, string> = {
50
52
  supplier: 'Supplier',
51
53
  }
52
54
 
53
- // Computed
54
- const filteredReagents = computed(() => {
55
- let result = [...(props.modelValue || [])]
56
-
57
- // Filter by search query
58
- if (searchQuery.value) {
59
- const query = searchQuery.value.toLowerCase()
60
- result = result.filter(
61
- (r) =>
62
- r.name.toLowerCase().includes(query) ||
63
- r.catalogNumber?.toLowerCase().includes(query) ||
64
- r.lotNumber?.toLowerCase().includes(query) ||
65
- r.supplier?.toLowerCase().includes(query)
66
- )
67
- }
68
-
69
- // Sort
70
- if (sortColumn.value) {
71
- const col = sortColumn.value
72
- result.sort((a, b) => {
73
- let aVal: string | number | null | undefined = getColumnValue(a, col) as string | number | null | undefined
74
- let bVal: string | number | null | undefined = getColumnValue(b, col) as string | number | null | undefined
75
-
76
- if (aVal === null || aVal === undefined) return 1
77
- if (bVal === null || bVal === undefined) return -1
78
-
79
- if (typeof aVal === 'string') aVal = aVal.toLowerCase()
80
- if (typeof bVal === 'string') bVal = bVal.toLowerCase()
55
+ const reagentSearch = useTextSearch({
56
+ items: () => props.modelValue || [],
57
+ query: searchQuery,
58
+ enabled: () => props.searchable,
59
+ getText: (reagent) => [
60
+ reagent.name,
61
+ reagent.catalogNumber,
62
+ reagent.lotNumber,
63
+ reagent.supplier,
64
+ ],
65
+ })
81
66
 
82
- if (aVal < bVal) return sortDirection.value === 'asc' ? -1 : 1
83
- if (aVal > bVal) return sortDirection.value === 'asc' ? 1 : -1
84
- return 0
85
- })
67
+ const reagentSort = computed(() => {
68
+ if (!sortColumn.value) return null
69
+ return {
70
+ key: sortColumn.value,
71
+ direction: sortDirection.value,
86
72
  }
73
+ })
87
74
 
88
- return result
75
+ const sortedReagents = useSortedItems<Reagent, ReagentColumn>({
76
+ items: reagentSearch.filteredItems,
77
+ sort: reagentSort,
78
+ caseSensitive: false,
79
+ getValue: (reagent, column) => getColumnValue(reagent, column),
89
80
  })
81
+ const filteredReagents = sortedReagents.sortedItems
90
82
 
91
83
  function getColumnValue(reagent: Reagent, column: ReagentColumn): unknown {
92
84
  switch (column) {
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  /** Collapsible tree visualizing the biological sample hierarchy (study → experiment → plate → sample → cell line → passage → clone → treatment). */
3
- import { ref, watch, type VNode } from 'vue'
4
- import { h, Transition } from 'vue'
3
+ import { h, Transition, type VNode } from 'vue'
5
4
  import type { TreeNodeType, BadgeVariant, TreeNode } from '../types'
5
+ import { useExpansionSet } from '../composables/useExpansionSet'
6
6
 
7
7
  interface Props {
8
8
  nodes: TreeNode[]
@@ -28,9 +28,6 @@ const emit = defineEmits<{
28
28
  'collapse': [nodeId: string]
29
29
  }>()
30
30
 
31
- // Track expanded nodes
32
- const expandedIds = ref<Set<string>>(new Set(props.defaultExpandedIds))
33
-
34
31
  // Default icons by type (Lucide SVG paths - arrays to support multi-path icons)
35
32
  interface IconElement {
36
33
  tag: 'path' | 'circle' | 'rect'
@@ -100,30 +97,22 @@ function collectAllIds(nodes: TreeNode[]): string[] {
100
97
  return ids
101
98
  }
102
99
 
103
- // Watch for expandAll changes
104
- watch(
105
- () => props.expandAll,
106
- (shouldExpandAll) => {
107
- if (shouldExpandAll) {
108
- expandedIds.value = new Set(collectAllIds(props.nodes))
109
- } else {
110
- expandedIds.value = new Set(props.defaultExpandedIds)
111
- }
112
- },
113
- { immediate: true }
114
- )
100
+ const expansion = useExpansionSet({
101
+ defaultIds: () => props.defaultExpandedIds,
102
+ allIds: () => collectAllIds(props.nodes),
103
+ expandAll: () => props.expandAll,
104
+ })
115
105
 
116
106
  function isExpanded(nodeId: string): boolean {
117
- return expandedIds.value.has(nodeId)
107
+ return expansion.isExpanded(nodeId)
118
108
  }
119
109
 
120
110
  function toggleExpand(node: TreeNode) {
121
- if (isExpanded(node.id)) {
122
- expandedIds.value.delete(node.id)
123
- emit('collapse', node.id)
124
- } else {
125
- expandedIds.value.add(node.id)
111
+ const expanded = expansion.toggle(node.id)
112
+ if (expanded) {
126
113
  emit('expand', node.id)
114
+ } else {
115
+ emit('collapse', node.id)
127
116
  }
128
117
  }
129
118
 
@@ -6,8 +6,11 @@ import BaseInput from './BaseInput.vue'
6
6
  import AutoGroupModal from './AutoGroupModal.vue'
7
7
  import type { SampleGroup } from '../types'
8
8
  import type { AutoGroupResult } from '../types/auto-group'
9
- import { deriveShade } from '../utils/color'
10
9
  import { DEFAULT_COLORS } from '../composables/useAutoGroup'
10
+ import { useTextSearch } from '../composables/useTextSearch'
11
+ import { useListSelection } from '../composables/useListSelection'
12
+ import { useSampleGroups, type SampleMajorGroup } from '../composables/useSampleGroups'
13
+ import { useExpansionSet } from '../composables/useExpansionSet'
11
14
 
12
15
  interface Props {
13
16
  samples: string[]
@@ -42,8 +45,8 @@ const showSmartGroupModal = ref(false)
42
45
  const newGroupName = ref('')
43
46
  const editingColor = ref<ColorEdit | null>(null)
44
47
  const colorPickerInput = ref<HTMLInputElement | null>(null)
45
- const expandedGroups = ref<Record<string, boolean>>({})
46
48
  const searchQuery = ref('')
49
+ const groupExpansion = useExpansionSet()
47
50
 
48
51
  // Sample Drag State
49
52
  const draggingSample = ref<string | null>(null)
@@ -63,184 +66,102 @@ const internalGroups = computed({
63
66
  set: (value) => emit('update:groups', value),
64
67
  })
65
68
 
66
- interface DisplaySubGroup extends SampleGroup {
67
- displayColor: string
68
- // Pre-built `displayColor + alpha` strings hoisted out of the template so
69
- // each render re-uses the same string reference instead of re-allocating.
70
- displayBg: string
71
- displayBorder: string
72
- }
73
-
74
- interface MajorGroup {
75
- name: string
76
- color: string
77
- subGroups: DisplaySubGroup[]
78
- allSamples: string[]
79
- }
80
-
81
- const hierarchicalGroups = computed<MajorGroup[]>(() => {
82
- const groups = internalGroups.value
83
- if (groups.length === 0) return []
84
-
85
- // Detect separator: use '/' if any group name contains it, otherwise '_'
86
- const separator = groups.some(g => g.name.includes('/')) ? '/' : '_'
87
- const majorGroupMap: Record<string, SampleGroup[]> = {}
88
-
89
- for (const group of groups) {
90
- const parts = group.name.split(separator)
91
- // Use first part as major group, or full name if no separator
92
- const majorPrefix = parts.length > 1 ? parts[0] : group.name
93
-
94
- if (!majorGroupMap[majorPrefix]) {
95
- majorGroupMap[majorPrefix] = []
96
- }
97
- majorGroupMap[majorPrefix].push(group)
98
- }
99
-
100
- const result: MajorGroup[] = []
101
-
102
- // Preserve insertion order from internalGroups so manual drag-reorder sticks.
103
- for (const [majorName, subGroups] of Object.entries(majorGroupMap)) {
104
- const allSamples = subGroups.flatMap(g => g.samples)
105
- const color = subGroups[0]?.color || '#3B82F6'
106
- const displaySubs: DisplaySubGroup[] = subGroups.map((sub, i) => {
107
- const displayColor = deriveShade(color, i, subGroups.length)
108
- return {
109
- ...sub,
110
- displayColor,
111
- displayBg: displayColor + '20',
112
- displayBorder: displayColor + '40',
113
- }
114
- })
115
-
116
- result.push({ name: majorName, color, subGroups: displaySubs, allSamples })
117
- }
118
-
119
- return result
120
- })
121
-
122
- // Check if hierarchy is meaningful (major groups have multiple sub-groups)
123
- // If each major group only has 1 sub-group with same name, show flat view instead
124
- const showHierarchy = computed(() => {
125
- const groups = hierarchicalGroups.value
126
- if (groups.length === 0) return false
127
-
128
- // Show hierarchy if any major group has multiple sub-groups
129
- // OR if major group name differs from its sub-group name
130
- return groups.some(major =>
131
- major.subGroups.length > 1 ||
132
- (major.subGroups.length === 1 && major.name !== major.subGroups[0].name)
133
- )
69
+ const sampleGroups = useSampleGroups({
70
+ samples: () => props.samples,
71
+ groups: internalGroups,
134
72
  })
73
+ const hierarchicalGroups = sampleGroups.hierarchicalGroups
74
+ const showHierarchy = sampleGroups.showHierarchy
135
75
 
136
76
  const groupingEnabled = computed(() => internalGroups.value.length > 0)
77
+ const ungroupedSamples = sampleGroups.ungroupedSamples
137
78
 
138
- const ungroupedSamples = computed(() => {
139
- const groupedSamples = new Set(
140
- internalGroups.value.flatMap(g => g.samples)
141
- )
142
- return props.samples.filter(s => !groupedSamples.has(s))
79
+ const sampleSearch = useTextSearch({
80
+ items: () => props.samples,
81
+ query: searchQuery,
82
+ getText: sample => sample,
143
83
  })
84
+ const filteredSamples = sampleSearch.filteredItems
144
85
 
145
- const filteredSamples = computed(() => {
146
- if (!searchQuery.value.trim()) return props.samples
147
- const query = searchQuery.value.toLowerCase()
148
- return props.samples.filter(s => s.toLowerCase().includes(query))
86
+ const sampleSelection = useListSelection({
87
+ selected: () => props.modelValue,
88
+ items: () => props.samples,
149
89
  })
150
-
151
-
152
- // Selection state
153
- const isAllSelected = computed(() =>
154
- props.samples.length > 0 && props.modelValue.length === props.samples.length
155
- )
90
+ const isAllSelected = sampleSelection.isAllSelected
156
91
 
157
92
  // Toggle functions
158
93
  function toggleSelectAll() {
159
- if (isAllSelected.value) {
160
- emit('update:modelValue', [])
161
- } else {
162
- emit('update:modelValue', [...props.samples])
163
- }
94
+ emit('update:modelValue', sampleSelection.toggleAll())
164
95
  }
165
96
 
166
97
  function toggleSample(sample: string) {
167
- const newSelection = props.modelValue.includes(sample)
168
- ? props.modelValue.filter(s => s !== sample)
169
- : [...props.modelValue, sample]
170
- emit('update:modelValue', newSelection)
98
+ emit('update:modelValue', sampleSelection.toggleValue(sample))
171
99
  }
172
100
 
173
101
  function toggleSamplesSelection(samples: string[]) {
174
- const allSelected = samples.every(s => props.modelValue.includes(s))
175
- const newSelection = allSelected
176
- ? props.modelValue.filter(s => !samples.includes(s))
177
- : [...props.modelValue, ...samples.filter(s => !props.modelValue.includes(s))]
178
-
179
- emit('update:modelValue', newSelection)
102
+ emit('update:modelValue', sampleSelection.toggleValues(samples))
180
103
  }
181
104
 
182
105
  function toggleGroupSamples(groupName: string) {
183
- const group = internalGroups.value.find(g => g.name === groupName)
106
+ const group = sampleGroups.findGroup(groupName)
184
107
  if (!group) return
185
108
  toggleSamplesSelection(group.samples)
186
109
  }
187
110
 
188
- function toggleMajorGroupSamples(majorGroup: MajorGroup) {
111
+ function toggleMajorGroupSamples(majorGroup: SampleMajorGroup) {
189
112
  toggleSamplesSelection(majorGroup.allSamples)
190
113
  }
191
114
 
192
115
  // Selection state checks
193
116
  function isFullySelected(samples: string[]): boolean {
194
- return samples.length > 0 && samples.every(s => props.modelValue.includes(s))
117
+ return sampleSelection.isFullySelected(samples)
195
118
  }
196
119
 
197
120
  function isPartiallySelected(samples: string[]): boolean {
198
- if (samples.length === 0) return false
199
- const selectedCount = samples.filter(s => props.modelValue.includes(s)).length
200
- return selectedCount > 0 && selectedCount < samples.length
121
+ return sampleSelection.isPartiallySelected(samples)
201
122
  }
202
123
 
203
124
  function isGroupFullySelected(groupName: string): boolean {
204
- const group = internalGroups.value.find(g => g.name === groupName)
125
+ const group = sampleGroups.findGroup(groupName)
205
126
  return group ? isFullySelected(group.samples) : false
206
127
  }
207
128
 
208
129
  function isGroupPartiallySelected(groupName: string): boolean {
209
- const group = internalGroups.value.find(g => g.name === groupName)
130
+ const group = sampleGroups.findGroup(groupName)
210
131
  return group ? isPartiallySelected(group.samples) : false
211
132
  }
212
133
 
213
- function isMajorGroupFullySelected(majorGroup: MajorGroup): boolean {
134
+ function isMajorGroupFullySelected(majorGroup: SampleMajorGroup): boolean {
214
135
  return isFullySelected(majorGroup.allSamples)
215
136
  }
216
137
 
217
- function isMajorGroupPartiallySelected(majorGroup: MajorGroup): boolean {
138
+ function isMajorGroupPartiallySelected(majorGroup: SampleMajorGroup): boolean {
218
139
  return isPartiallySelected(majorGroup.allSamples)
219
140
  }
220
141
 
221
142
  // Expand/collapse
222
143
  function toggleGroupExpanded(groupName: string) {
223
- expandedGroups.value[groupName] = !expandedGroups.value[groupName]
144
+ groupExpansion.toggle(groupName)
224
145
  }
225
146
 
226
147
  function isGroupExpanded(groupName: string): boolean {
227
- return !!expandedGroups.value[groupName]
148
+ return groupExpansion.isExpanded(groupName)
228
149
  }
229
150
 
230
151
  function expandAllGroups() {
231
- const expanded: Record<string, boolean> = {}
152
+ const expanded: string[] = []
232
153
  for (const major of hierarchicalGroups.value) {
233
- expanded[`major:${major.name}`] = true
154
+ expanded.push(`major:${major.name}`)
234
155
  for (const sub of major.subGroups) {
235
- expanded[sub.name] = true
156
+ expanded.push(sub.name)
236
157
  }
237
158
  }
238
- expanded['__ungrouped__'] = true
239
- expandedGroups.value = expanded
159
+ expanded.push('__ungrouped__')
160
+ groupExpansion.setExpanded(expanded)
240
161
  }
241
162
 
242
163
  function collapseAllGroups() {
243
- expandedGroups.value = {}
164
+ groupExpansion.collapseAll()
244
165
  }
245
166
 
246
167
  // Smart group
@@ -254,7 +175,7 @@ function clearGroups() {
254
175
  internalGroups.value = []
255
176
  }
256
177
 
257
- function deleteMajorGroup(majorGroup: MajorGroup) {
178
+ function deleteMajorGroup(majorGroup: SampleMajorGroup) {
258
179
  internalGroups.value = internalGroups.value.filter(
259
180
  g => !majorGroup.subGroups.some(sg => sg.name === g.name)
260
181
  )
@@ -452,7 +373,7 @@ function openColorPicker(groupName: string, event: Event) {
452
373
  colorPickerInput.value?.click()
453
374
  }
454
375
 
455
- function openMajorGroupColorPicker(majorGroup: MajorGroup, event: Event) {
376
+ function openMajorGroupColorPicker(majorGroup: SampleMajorGroup, event: Event) {
456
377
  event.stopPropagation()
457
378
  editingColor.value = { kind: 'family', names: majorGroup.subGroups.map(sg => sg.name) }
458
379
  colorPickerInput.value?.click()
@@ -473,8 +394,7 @@ function handleColorChange(event: Event) {
473
394
  }
474
395
 
475
396
  function getGroupColor(groupName: string): string {
476
- const group = internalGroups.value.find(g => g.name === groupName)
477
- return group?.color || '#3B82F6'
397
+ return sampleGroups.getGroupColor(groupName)
478
398
  }
479
399
 
480
400
  const colorPickerSeed = computed(() => {
@@ -1,10 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  /** Renders a segmented button group for single-option selection, with simple or solid variants. */
3
- import type { SegmentedOption, SegmentedControlVariant, SegmentedControlSize } from '../types'
3
+ import { computed } from 'vue'
4
+ import type { SegmentedOption, SegmentedOptionInput, SegmentedControlVariant, SegmentedControlSize } from '../types'
5
+ import { normalizeOptionInput } from '../utils/options'
4
6
 
5
7
  interface Props {
6
8
  modelValue: string | number
7
- options: SegmentedOption[]
9
+ options: SegmentedOptionInput[]
8
10
  variant?: SegmentedControlVariant
9
11
  size?: SegmentedControlSize
10
12
  fullWidth?: boolean
@@ -22,6 +24,8 @@ const emit = defineEmits<{
22
24
  'update:modelValue': [value: string | number]
23
25
  }>()
24
26
 
27
+ const normalizedOptions = computed<SegmentedOption[]>(() => props.options.map(normalizeOptionInput))
28
+
25
29
  function handleSelect(option: SegmentedOption) {
26
30
  if (props.disabled || option.disabled) return
27
31
  emit('update:modelValue', option.value)
@@ -47,7 +51,7 @@ function handleKeydown(event: KeyboardEvent, option: SegmentedOption) {
47
51
  role="radiogroup"
48
52
  >
49
53
  <button
50
- v-for="option in options"
54
+ v-for="option in normalizedOptions"
51
55
  :key="String(option.value)"
52
56
  type="button"
53
57
  role="radio"
@@ -5,7 +5,7 @@ const sizes: ('sm' | 'md' | 'lg')[] = ['sm', 'md', 'lg']
5
5
  </script>
6
6
 
7
7
  <template>
8
- <Story title="Action/SettingsButton">
8
+ <Story title="Action/Deprecated/SettingsButton">
9
9
  <Variant title="Playground">
10
10
  <template #default="{ state }">
11
11
  <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
- /** Gear icon button that toggles a dropdown panel for inline settings content, closing on outside click. */
3
- import { ref, onMounted, onUnmounted } from 'vue'
2
+ /** @deprecated Use AppTopBar settingsConfig or SettingsModal instead. */
3
+ import { useDropdownState } from '../composables/useDropdownState'
4
+ import IconButton from './IconButton.vue'
4
5
 
5
6
  interface Props {
6
7
  size?: 'sm' | 'md' | 'lg'
@@ -14,41 +15,28 @@ const emit = defineEmits<{
14
15
  click: [event: MouseEvent]
15
16
  }>()
16
17
 
17
- const isOpen = ref(false)
18
- const dropdownRef = ref<HTMLElement | null>(null)
18
+ const { isOpen, rootRef, toggle: toggleDropdown } = useDropdownState({
19
+ closeOnEscape: false,
20
+ })
19
21
 
20
22
  function toggle(event: MouseEvent) {
21
- isOpen.value = !isOpen.value
23
+ toggleDropdown()
22
24
  emit('click', event)
23
25
  }
24
-
25
- function handleClickOutside(event: MouseEvent) {
26
- const target = event.target as Node
27
- if (dropdownRef.value && !dropdownRef.value.contains(target)) {
28
- isOpen.value = false
29
- }
30
- }
31
-
32
- onMounted(() => {
33
- document.addEventListener('click', handleClickOutside)
34
- })
35
-
36
- onUnmounted(() => {
37
- document.removeEventListener('click', handleClickOutside)
38
- })
39
26
  </script>
40
27
 
41
28
  <template>
42
- <div ref="dropdownRef" class="mint-settings-button">
43
- <button
44
- type="button"
45
- :class="['mint-settings-button__trigger', `mint-settings-button__trigger--${size}`]"
46
- aria-label="Settings"
29
+ <div ref="rootRef" class="mint-settings-button">
30
+ <IconButton
31
+ class="mint-settings-button__trigger"
32
+ label="Settings"
33
+ variant="ghost"
34
+ :size="size"
47
35
  @click.stop="toggle"
48
36
  >
49
37
  <!-- Settings/Gear icon -->
50
38
  <svg
51
- :class="`mint-settings-button__icon--${size}`"
39
+ class="mint-settings-button__icon"
52
40
  viewBox="0 0 24 24"
53
41
  fill="none"
54
42
  stroke="currentColor"
@@ -58,7 +46,7 @@ onUnmounted(() => {
58
46
  >
59
47
  <path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /><circle cx="12" cy="12" r="3" />
60
48
  </svg>
61
- </button>
49
+ </IconButton>
62
50
 
63
51
  <!-- Dropdown panel -->
64
52
  <div v-show="isOpen" class="mint-settings-dropdown">
@@ -109,7 +109,7 @@ const outlierOptions: SelectOption<string>[] = [
109
109
 
110
110
  // ─────────── Schema-driven (recommended) ───────────
111
111
  // Plugin authors describe parameters once; the modal auto-renders every field
112
- // via the SDK's FormFieldRenderer registry. Compare to the "Vertical Layout"
112
+ // via the SDK form field registry. Compare to the "Vertical Layout"
113
113
  // variant above, which builds the same surface manually.
114
114
  const schemaSettings = ref<Record<string, unknown>>({
115
115
  pluginName: 'IC50 Calculator',