@morscherlab/mint-sdk 1.2.0-beta.8 → 1.2.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 (402) hide show
  1. package/README.md +60 -0
  2. package/dist/{ExperimentPopover-CfOdh5Rm.js → ExperimentPopover-CJdNlCZb.js} +24 -15
  3. package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DvIagrxY.js → ExperimentSelectorModal-DCXmwKNS.js} +5 -5
  5. package/dist/ExperimentSelectorModal-DCXmwKNS.js.map +1 -0
  6. package/dist/{SettingsModal-W3TYfnP9.js → SettingsModal-BYR20I4c.js} +5 -5
  7. package/dist/SettingsModal-BYR20I4c.js.map +1 -0
  8. package/dist/{EmptyState-NBqf2_8z.js → Skeleton-BAF3CKY7.js} +111 -93
  9. package/dist/Skeleton-BAF3CKY7.js.map +1 -0
  10. package/dist/__tests__/components/DataStates.test.d.ts +1 -0
  11. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  12. package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
  13. package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
  14. package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
  15. package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
  16. package/dist/__tests__/components/iconButtonIconSizing.test.d.ts +1 -0
  17. package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  19. package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
  20. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  21. package/dist/apiErrors.d.ts +26 -0
  22. package/dist/components/ActionMenu.vue.d.ts +1 -1
  23. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  24. package/dist/components/AuditTrail.vue.d.ts +13 -0
  25. package/dist/components/BaseInput.vue.d.ts +1 -1
  26. package/dist/components/BaseSelect.vue.d.ts +1 -1
  27. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  28. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  29. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  30. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
  31. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  32. package/dist/components/DataFrame.vue.d.ts +14 -2
  33. package/dist/components/DatePicker.vue.d.ts +2 -2
  34. package/dist/components/DateTimePicker.vue.d.ts +3 -1
  35. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  36. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  37. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  38. package/dist/components/FileBrowserModal.vue.d.ts +99 -0
  39. package/dist/components/FilePicker.vue.d.ts +32 -0
  40. package/dist/components/FileUploader.vue.d.ts +5 -2
  41. package/dist/components/FormulaInput.vue.d.ts +1 -1
  42. package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
  43. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  44. package/dist/components/MobileSupportGate.vue.d.ts +1 -1
  45. package/dist/components/MoleculeInput.vue.d.ts +1 -1
  46. package/dist/components/NumberInput.vue.d.ts +1 -1
  47. package/dist/components/PlotlyChart.vue.d.ts +59 -0
  48. package/dist/components/ProgressBar.vue.d.ts +1 -1
  49. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  50. package/dist/components/ReagentList.vue.d.ts +29 -1
  51. package/dist/components/ResourceCard.vue.d.ts +1 -1
  52. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  53. package/dist/components/SampleSelector.drag.d.ts +13 -0
  54. package/dist/components/SampleSelector.tree.d.ts +2 -0
  55. package/dist/components/SampleSelector.vue.d.ts +34 -1
  56. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  57. package/dist/components/SecretInput.vue.d.ts +1 -1
  58. package/dist/components/SequenceInput.vue.d.ts +1 -1
  59. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -0
  60. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  61. package/dist/components/TagsInput.vue.d.ts +1 -1
  62. package/dist/components/TimePicker.vue.d.ts +2 -1
  63. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  64. package/dist/components/UnitInput.vue.d.ts +1 -1
  65. package/dist/components/WellPlate.geometry.d.ts +15 -0
  66. package/dist/components/WellPlate.interaction.d.ts +13 -0
  67. package/dist/components/WellPlate.vue.d.ts +30 -1
  68. package/dist/components/fileBrowserPresentation.d.ts +10 -0
  69. package/dist/components/index.d.ts +4 -0
  70. package/dist/components/index.js +8 -8
  71. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  72. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  73. package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
  74. package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
  75. package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
  76. package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
  77. package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
  78. package/dist/{components-B80gV0P6.js → components-DIum5hkx.js} +5415 -2753
  79. package/dist/components-DIum5hkx.js.map +1 -0
  80. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  81. package/dist/composables/filePicker/localFiles.d.ts +3 -0
  82. package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
  83. package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
  84. package/dist/composables/filePicker/validation.d.ts +5 -0
  85. package/dist/composables/index.d.ts +3 -0
  86. package/dist/composables/index.js +10 -10
  87. package/dist/composables/useApi.d.ts +14 -7
  88. package/dist/composables/useDropdownState.d.ts +18 -2
  89. package/dist/composables/useEventStream.d.ts +9 -0
  90. package/dist/composables/useFileBrowser.d.ts +55 -0
  91. package/dist/composables/useFilePicker.d.ts +189 -0
  92. package/dist/composables/useListReorder.d.ts +90 -0
  93. package/dist/composables/useMenuKeyboard.d.ts +2 -2
  94. package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
  95. package/dist/composables/usePluginConfig.d.ts +3 -1
  96. package/dist/composables/useRequestSyncState.d.ts +42 -2
  97. package/dist/composables/useScheduleDrag.d.ts +1 -0
  98. package/dist/{composables-C8mmD5ta.js → composables-mFXsTA4g.js} +307 -74
  99. package/dist/composables-mFXsTA4g.js.map +1 -0
  100. package/dist/{useApi-CDBq6z23.js → errors-BLuqMee5.js} +178 -16
  101. package/dist/errors-BLuqMee5.js.map +1 -0
  102. package/dist/{experiment-Y9Iz7KYi.js → experiment-CVDRAnqp.js} +3 -8
  103. package/dist/experiment-CVDRAnqp.js.map +1 -0
  104. package/dist/{experiment-utils-DV3DrvE_.js → experiment-utils-CV2Wza3z.js} +1 -1
  105. package/dist/experiment-utils-CV2Wza3z.js.map +1 -0
  106. package/dist/index.d.ts +1 -0
  107. package/dist/index.js +15 -15
  108. package/dist/install.js +2 -7
  109. package/dist/install.js.map +1 -1
  110. package/dist/permissions.d.ts +42 -1
  111. package/dist/permissions.js +20 -10
  112. package/dist/permissions.js.map +1 -1
  113. package/dist/stores/index.d.ts +1 -1
  114. package/dist/stores/index.js +3 -3
  115. package/dist/stores/settings.d.ts +31 -1
  116. package/dist/styles.css +15162 -32475
  117. package/dist/templates/index.js +2 -4
  118. package/dist/{templates-CK72aKO1.js → templates-CmGfmBRA.js} +291 -85
  119. package/dist/templates-CmGfmBRA.js.map +1 -0
  120. package/dist/types/fileBrowserTypes.d.ts +77 -0
  121. package/dist/types/filePicker.d.ts +77 -0
  122. package/dist/types/index.d.ts +2 -0
  123. package/dist/{useControlSchema-_OVhavKq.js → useControlSchema-DldpxNOP.js} +234 -1121
  124. package/dist/useControlSchema-DldpxNOP.js.map +1 -0
  125. package/dist/{useDropdownState-D5G4UvWd.js → useDropdownState-C7hRiVQf.js} +22 -6
  126. package/dist/useDropdownState-C7hRiVQf.js.map +1 -0
  127. package/dist/{useExperimentSelector-DSEckf_g.js → useExperimentSelector-CEcIaueJ.js} +4 -4
  128. package/dist/{useExperimentSelector-DSEckf_g.js.map → useExperimentSelector-CEcIaueJ.js.map} +1 -1
  129. package/dist/{useFormBuilder-Bd714C7y.js → useFormBuilder-z5L_dUIy.js} +2 -2
  130. package/dist/{useFormBuilder-Bd714C7y.js.map → useFormBuilder-z5L_dUIy.js.map} +1 -1
  131. package/dist/utils/color.d.ts +13 -0
  132. package/dist/utils/errors.d.ts +9 -0
  133. package/dist/{useProtocolTemplates-Dq5Pzwyd.js → validation-uwoJGEb6.js} +231 -158
  134. package/dist/validation-uwoJGEb6.js.map +1 -0
  135. package/package.json +1 -1
  136. package/src/__tests__/apiErrors.test.ts +81 -0
  137. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  138. package/src/__tests__/components/DataFrame.test.ts +183 -11
  139. package/src/__tests__/components/DataStates.test.ts +176 -0
  140. package/src/__tests__/components/DatePicker.test.ts +76 -0
  141. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  142. package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
  143. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  144. package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
  145. package/src/__tests__/components/FilePicker.state.test.ts +287 -0
  146. package/src/__tests__/components/FilePicker.test.ts +487 -0
  147. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
  148. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  149. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  150. package/src/__tests__/components/PlotlyChart.test.ts +305 -0
  151. package/src/__tests__/components/RackEditor.test.ts +35 -0
  152. package/src/__tests__/components/ReagentList.test.ts +64 -2
  153. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  154. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  155. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  156. package/src/__tests__/components/SegmentedControl.test.ts +107 -0
  157. package/src/__tests__/components/TimePicker.test.ts +61 -0
  158. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  159. package/src/__tests__/components/iconButtonIconSizing.test.ts +18 -0
  160. package/src/__tests__/composables/useApi.test.ts +92 -9
  161. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  162. package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
  163. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
  164. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  165. package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
  166. package/src/__tests__/composables/usePluginClient.test.ts +3 -0
  167. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  168. package/src/__tests__/stores/settings.test.ts +71 -1
  169. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  170. package/src/__tests__/utils/permissions.test.ts +68 -0
  171. package/src/apiErrors.ts +85 -0
  172. package/src/components/ActionMenu.vue +45 -88
  173. package/src/components/AlertBox.vue +0 -4
  174. package/src/components/AppAvatarMenu.vue +2 -14
  175. package/src/components/AppLayout.vue +0 -4
  176. package/src/components/AppPluginSwitcher.story.vue +87 -0
  177. package/src/components/AppPluginSwitcher.vue +2 -5
  178. package/src/components/AppSidebar.vue +0 -4
  179. package/src/components/AppToastContainer.vue +6 -8
  180. package/src/components/AppTopBar.vue +0 -4
  181. package/src/components/ArtifactSaveDialog.vue +0 -4
  182. package/src/components/ArtifactSelectorModal.vue +0 -4
  183. package/src/components/AuditTrail.story.vue +18 -0
  184. package/src/components/AuditTrail.vue +27 -7
  185. package/src/components/AutoGroupModal.vue +0 -4
  186. package/src/components/Avatar.vue +0 -4
  187. package/src/components/BaseButton.vue +0 -4
  188. package/src/components/BaseCheckbox.vue +0 -4
  189. package/src/components/BaseInput.vue +0 -4
  190. package/src/components/BaseModal.vue +0 -4
  191. package/src/components/BasePill.vue +0 -4
  192. package/src/components/BaseRadioGroup.vue +0 -4
  193. package/src/components/BaseSelect.vue +0 -4
  194. package/src/components/BaseSlider.vue +0 -4
  195. package/src/components/BaseTabs.vue +0 -4
  196. package/src/components/BaseTextarea.vue +0 -4
  197. package/src/components/BaseToggle.vue +0 -4
  198. package/src/components/BatchProgressList.story.vue +18 -0
  199. package/src/components/BatchProgressList.vue +32 -4
  200. package/src/components/Breadcrumb.vue +0 -4
  201. package/src/components/Calendar.vue +0 -4
  202. package/src/components/ChartContainer.story.vue +1 -1
  203. package/src/components/ChartContainer.vue +0 -4
  204. package/src/components/ChemicalFormula.vue +0 -4
  205. package/src/components/CollapsibleCard.vue +0 -4
  206. package/src/components/ColorSlider.vue +0 -4
  207. package/src/components/ConcentrationInput.vue +0 -4
  208. package/src/components/ConfirmDialog.vue +0 -4
  209. package/src/components/DataFrame.story.vue +14 -0
  210. package/src/components/DataFrame.vue +97 -23
  211. package/src/components/DatePicker.vue +73 -27
  212. package/src/components/DateTimePicker.vue +45 -17
  213. package/src/components/Divider.vue +0 -4
  214. package/src/components/DoseCalculator.vue +0 -4
  215. package/src/components/DropdownButton.vue +2 -14
  216. package/src/components/EmptyState.vue +0 -4
  217. package/src/components/ExperimentCodeBadge.vue +0 -4
  218. package/src/components/ExperimentDataViewer.story.vue +3 -0
  219. package/src/components/ExperimentDataViewer.vue +33 -13
  220. package/src/components/ExperimentPopover.vue +12 -7
  221. package/src/components/ExperimentSelectorModal.vue +0 -4
  222. package/src/components/ExperimentTimeline.story.vue +18 -0
  223. package/src/components/ExperimentTimeline.vue +81 -75
  224. package/src/components/FileBrowserModal.story.vue +203 -0
  225. package/src/components/FileBrowserModal.vue +384 -0
  226. package/src/components/FilePicker.story.vue +44 -0
  227. package/src/components/FilePicker.vue +284 -0
  228. package/src/components/FileUploader.vue +32 -18
  229. package/src/components/FitPanel.vue +0 -4
  230. package/src/components/FormActions.story.vue +96 -0
  231. package/src/components/FormActions.vue +0 -4
  232. package/src/components/FormBuilder.vue +0 -4
  233. package/src/components/FormField.vue +0 -4
  234. package/src/components/FormulaInput.vue +0 -4
  235. package/src/components/GeneratedPathInput.story.vue +68 -0
  236. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  237. package/src/components/GeneratedPlotlyResult.vue +34 -69
  238. package/src/components/GeneratedPluginView.story.vue +145 -0
  239. package/src/components/GeneratedPluginView.vue +10 -10
  240. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  241. package/src/components/GeneratedResultRenderer.vue +4 -9
  242. package/src/components/GroupAssigner.vue +67 -5
  243. package/src/components/IconButton.vue +0 -4
  244. package/src/components/InstrumentAlertLog.vue +0 -4
  245. package/src/components/InstrumentStateBadge.vue +0 -4
  246. package/src/components/InstrumentStatusCard.vue +0 -4
  247. package/src/components/JobsStatusTray.vue +0 -4
  248. package/src/components/LcmsSequenceTable.vue +81 -50
  249. package/src/components/LoadingSpinner.vue +0 -4
  250. package/src/components/MobileSupportGate.vue +0 -4
  251. package/src/components/MoleculeInput.vue +0 -4
  252. package/src/components/MultiSelect.vue +0 -4
  253. package/src/components/NumberInput.vue +0 -4
  254. package/src/components/PlateMapEditor.vue +3 -14
  255. package/src/components/PlotlyChart.story.vue +61 -0
  256. package/src/components/PlotlyChart.vue +233 -0
  257. package/src/components/PluginIcon.vue +0 -4
  258. package/src/components/ProgressBar.vue +0 -4
  259. package/src/components/ProtocolStepEditor.vue +2 -4
  260. package/src/components/RackEditor.vue +51 -70
  261. package/src/components/ReagentEditor.vue +0 -4
  262. package/src/components/ReagentList.story.vue +18 -0
  263. package/src/components/ReagentList.vue +127 -82
  264. package/src/components/ResourceCard.vue +0 -4
  265. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  266. package/src/components/RuntimeUpdateNotice.vue +4 -4
  267. package/src/components/SampleHierarchyTree.story.vue +18 -0
  268. package/src/components/SampleHierarchyTree.vue +32 -9
  269. package/src/components/SampleLegend.vue +2 -8
  270. package/src/components/SampleSelector.drag.ts +51 -0
  271. package/src/components/SampleSelector.story.vue +6 -0
  272. package/src/components/SampleSelector.tree.ts +2 -0
  273. package/src/components/SampleSelector.vue +49 -10
  274. package/src/components/SampleSelectorGroupNode.vue +19 -0
  275. package/src/components/ScheduleCalendar.story.vue +6 -0
  276. package/src/components/ScheduleCalendar.vue +82 -7
  277. package/src/components/ScientificNumber.vue +0 -4
  278. package/src/components/SectionCard.vue +0 -4
  279. package/src/components/SegmentedControl.vue +50 -7
  280. package/src/components/SequenceInput.vue +0 -4
  281. package/src/components/SequenceProgressBar.story.vue +110 -0
  282. package/src/components/SequenceProgressBar.vue +0 -4
  283. package/src/components/SettingsModal.vue +0 -4
  284. package/src/components/Skeleton.vue +0 -4
  285. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  286. package/src/components/SmartGroupManual.vue +0 -4
  287. package/src/components/StatusIndicator.vue +0 -4
  288. package/src/components/StepWizard.vue +0 -4
  289. package/src/components/TagsInput.vue +4 -6
  290. package/src/components/ThemeToggle.vue +0 -4
  291. package/src/components/TimePicker.vue +36 -7
  292. package/src/components/TimeRangeInput.vue +0 -4
  293. package/src/components/Tooltip.story.vue +3 -3
  294. package/src/components/Tooltip.vue +0 -4
  295. package/src/components/UnitInput.vue +0 -4
  296. package/src/components/WellPlate.geometry.ts +60 -1
  297. package/src/components/WellPlate.interaction.ts +44 -0
  298. package/src/components/WellPlate.story.vue +8 -0
  299. package/src/components/WellPlate.vue +53 -7
  300. package/src/components/fileBrowserPresentation.ts +39 -0
  301. package/src/components/index.ts +5 -0
  302. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  303. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  304. package/src/components/internal/DataStateInternal.vue +74 -0
  305. package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
  306. package/src/components/internal/FileBrowserListingInternal.vue +197 -0
  307. package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
  308. package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
  309. package/src/components/internal/FilePickerTreeInternal.vue +238 -0
  310. package/src/components/internal/FormSectionRenderer.vue +0 -4
  311. package/src/components/internal/WellEditPopupInternal.vue +0 -4
  312. package/src/composables/controlSchemaTypes.ts +34 -0
  313. package/src/composables/filePicker/localFiles.ts +58 -0
  314. package/src/composables/filePicker/usePickerNavigation.ts +220 -0
  315. package/src/composables/filePicker/usePickerSelection.ts +259 -0
  316. package/src/composables/filePicker/validation.ts +41 -0
  317. package/src/composables/index.ts +17 -0
  318. package/src/composables/useApi.ts +57 -13
  319. package/src/composables/useDropdownState.ts +35 -5
  320. package/src/composables/useEventStream.ts +14 -2
  321. package/src/composables/useFileBrowser.ts +314 -0
  322. package/src/composables/useFileImport.ts +2 -7
  323. package/src/composables/useFilePicker.ts +366 -0
  324. package/src/composables/useGeneratedAnalysis.ts +18 -26
  325. package/src/composables/useListReorder.story.vue +143 -0
  326. package/src/composables/useListReorder.ts +242 -0
  327. package/src/composables/useMenuKeyboard.ts +2 -2
  328. package/src/composables/useOptimisticMutation.ts +1 -15
  329. package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
  330. package/src/composables/usePluginClient.ts +3 -0
  331. package/src/composables/usePluginConfig.ts +3 -1
  332. package/src/composables/useRackEditor.ts +2 -11
  333. package/src/composables/useRequestSyncState.ts +98 -28
  334. package/src/composables/useResourceCrud.ts +1 -15
  335. package/src/composables/useScheduleDrag.ts +37 -0
  336. package/src/composables/useWellPainting.ts +5 -29
  337. package/src/composables/useWellPlateEditor.ts +1 -11
  338. package/src/index.ts +3 -0
  339. package/src/permissions.ts +48 -9
  340. package/src/stores/experiment.ts +2 -7
  341. package/src/stores/index.ts +9 -1
  342. package/src/stores/settings.ts +93 -1
  343. package/src/styles/components/audit-trail.css +5 -5
  344. package/src/styles/components/batch-progress-list.css +7 -0
  345. package/src/styles/components/color-slider.css +2 -2
  346. package/src/styles/components/data-state.css +30 -0
  347. package/src/styles/components/dataframe.css +29 -35
  348. package/src/styles/components/experiment-data-viewer.css +4 -4
  349. package/src/styles/components/experiment-timeline.css +3 -30
  350. package/src/styles/components/file-browser-modal.css +489 -0
  351. package/src/styles/components/file-picker.css +502 -0
  352. package/src/styles/components/form-builder.css +5 -5
  353. package/src/styles/components/icon-button.css +9 -0
  354. package/src/styles/components/lcms-sequence-table.css +16 -1
  355. package/src/styles/components/multi-select.css +1 -1
  356. package/src/styles/components/reagent-list.css +38 -31
  357. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  358. package/src/styles/components/sample-selector.css +9 -2
  359. package/src/styles/components/schedule-calendar.css +8 -0
  360. package/src/styles/components/scientific-number.css +1 -1
  361. package/src/styles/components/well-plate.css +8 -0
  362. package/src/styles/index.css +11 -0
  363. package/src/styles/variables.css +29 -0
  364. package/src/templates/builderPresetControls.ts +1 -1
  365. package/src/templates/componentPlateHelpers.ts +3 -1
  366. package/src/templates/doseResponseAdapters.ts +2 -13
  367. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  368. package/src/templates/plateMapBuilder.ts +2 -2
  369. package/src/templates/qpcrPlateBuilder.ts +1 -1
  370. package/src/templates/templateValidators.ts +1 -1
  371. package/src/templates/timeCourseBuilder.ts +2 -2
  372. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  373. package/src/types/fileBrowserTypes.ts +85 -0
  374. package/src/types/filePicker.ts +72 -0
  375. package/src/types/index.ts +14 -0
  376. package/src/utils/color.ts +51 -0
  377. package/src/utils/errors.ts +29 -0
  378. package/dist/EmptyState-NBqf2_8z.js.map +0 -1
  379. package/dist/ExperimentPopover-CfOdh5Rm.js.map +0 -1
  380. package/dist/ExperimentSelectorModal-DvIagrxY.js.map +0 -1
  381. package/dist/SettingsModal-W3TYfnP9.js.map +0 -1
  382. package/dist/components-B80gV0P6.js.map +0 -1
  383. package/dist/composables/autoGroupConstants.d.ts +0 -1
  384. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  385. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  386. package/dist/composables-C8mmD5ta.js.map +0 -1
  387. package/dist/experiment-Y9Iz7KYi.js.map +0 -1
  388. package/dist/experiment-utils-DV3DrvE_.js.map +0 -1
  389. package/dist/templates/builderDefaults.d.ts +0 -1
  390. package/dist/templates/plateGeometry.d.ts +0 -4
  391. package/dist/templates-CK72aKO1.js.map +0 -1
  392. package/dist/useApi-CDBq6z23.js.map +0 -1
  393. package/dist/useControlSchema-_OVhavKq.js.map +0 -1
  394. package/dist/useDropdownState-D5G4UvWd.js.map +0 -1
  395. package/dist/useProtocolTemplates-Dq5Pzwyd.js.map +0 -1
  396. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  397. package/src/composables/autoGroupConstants.ts +0 -4
  398. package/src/composables/autoGroupGrouping.ts +0 -148
  399. package/src/composables/useAutoGroupInputSources.ts +0 -147
  400. package/src/templates/builderDefaults.ts +0 -11
  401. package/src/templates/plateGeometry.ts +0 -62
  402. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → apiErrors.test.d.ts} +0 -0
@@ -25,6 +25,7 @@ import {
25
25
  removeSampleFromGroup as removeSampleFromSampleGroup,
26
26
  removeSampleGroups,
27
27
  } from './SampleSelector.groups'
28
+ import DataStateInternal from './internal/DataStateInternal.vue'
28
29
 
29
30
  interface Props {
30
31
  samples?: string[]
@@ -35,6 +36,15 @@ interface Props {
35
36
  experimentId?: number
36
37
  designData?: Record<string, unknown>
37
38
  autoloadExperimentData?: boolean
39
+ /** Replace the selector body with a loading placeholder. */
40
+ loading?: boolean
41
+ /**
42
+ * Error message. When set, the selector body is replaced by an error state.
43
+ * `null`/`undefined` renders normally.
44
+ */
45
+ error?: string | null
46
+ /** Empty-state headline shown when there are no samples to select from. */
47
+ emptyMessage?: string
38
48
  }
39
49
 
40
50
  const props = withDefaults(defineProps<Props>(), {
@@ -45,6 +55,9 @@ const props = withDefaults(defineProps<Props>(), {
45
55
  experimentId: undefined,
46
56
  designData: undefined,
47
57
  autoloadExperimentData: true,
58
+ loading: false,
59
+ error: null,
60
+ emptyMessage: 'No samples available',
48
61
  })
49
62
 
50
63
  const emit = defineEmits<{
@@ -69,6 +82,8 @@ const internalGroups = computed({
69
82
  })
70
83
 
71
84
  const {
85
+ announcement: reorderAnnouncement,
86
+ announcerStyle,
72
87
  draggingSample,
73
88
  dragOverGroup,
74
89
  draggingGroup,
@@ -81,6 +96,7 @@ const {
81
96
  handleDragLeave,
82
97
  handleDrop,
83
98
  handleGroupDragStart,
99
+ handleGroupReorderKeydown,
84
100
  handleGroupDragEnd,
85
101
  handleGroupDragOver,
86
102
  handleGroupDragLeave,
@@ -227,6 +243,7 @@ const treeContext = computed<SampleGroupTreeContext>(() => ({
227
243
  onGroupDragOver: handleGroupDragOver,
228
244
  onGroupDragLeave: handleGroupDragLeave,
229
245
  onGroupDrop: handleGroupDrop,
246
+ onGroupReorderKeydown: handleGroupReorderKeydown,
230
247
  }))
231
248
 
232
249
  // New group
@@ -237,13 +254,36 @@ function addNewGroup() {
237
254
  newGroupName.value = ''
238
255
  }
239
256
 
257
+ /** True while a loading, error or empty placeholder stands in for the body. */
258
+ const isPlaceholderState = computed(() =>
259
+ props.loading || Boolean(props.error) || resolvedSamples.value.length === 0,
260
+ )
261
+
240
262
  defineExpose({ handleSmartGroupApply })
241
263
  </script>
242
264
 
243
265
  <template>
244
266
  <div class="mint-sample-selector">
267
+ <div v-if="error" class="mint-sample-selector__state">
268
+ <slot name="error" :error="error">
269
+ <DataStateInternal state="error" size="sm" :title="error" />
270
+ </slot>
271
+ </div>
272
+
273
+ <div v-else-if="loading" class="mint-sample-selector__state">
274
+ <slot name="loading">
275
+ <DataStateInternal state="loading" size="sm" loading-label="Loading samples" />
276
+ </slot>
277
+ </div>
278
+
279
+ <div v-else-if="resolvedSamples.length === 0" class="mint-sample-selector__state">
280
+ <slot name="empty">
281
+ <DataStateInternal state="empty" size="sm" :title="emptyMessage" />
282
+ </slot>
283
+ </div>
284
+
245
285
  <!-- Select All Row -->
246
- <label class="mint-sample-selector__select-all">
286
+ <label v-if="!isPlaceholderState" class="mint-sample-selector__select-all">
247
287
  <input
248
288
  type="checkbox"
249
289
  :checked="isAllSelected"
@@ -255,7 +295,7 @@ defineExpose({ handleSmartGroupApply })
255
295
  </label>
256
296
 
257
297
  <!-- Action Buttons Row -->
258
- <div v-if="enableGrouping" class="mint-sample-selector__actions">
298
+ <div v-if="!isPlaceholderState && enableGrouping" class="mint-sample-selector__actions">
259
299
  <div class="mint-sample-selector__actions-row">
260
300
  <!-- Grouping Button -->
261
301
  <BaseButton
@@ -291,7 +331,7 @@ defineExpose({ handleSmartGroupApply })
291
331
  </div>
292
332
 
293
333
  <!-- Grouped View -->
294
- <div v-if="groupingEnabled" class="mint-sample-selector__grouped">
334
+ <div v-if="!isPlaceholderState && groupingEnabled" class="mint-sample-selector__grouped">
295
335
  <!-- Groups Header -->
296
336
  <div class="mint-sample-selector__groups-header">
297
337
  <span class="mint-sample-selector__groups-title">Groups ({{ internalGroups.length }})</span>
@@ -320,7 +360,7 @@ defineExpose({ handleSmartGroupApply })
320
360
  />
321
361
 
322
362
  <!-- Empty state -->
323
- <div v-if="internalGroups.length === 0" class="mint-sample-selector__empty">
363
+ <div v-if="internalGroups.length === 0" class="mint-sample-selector__hint">
324
364
  Click Smart to auto-group samples
325
365
  </div>
326
366
  </div>
@@ -394,7 +434,7 @@ defineExpose({ handleSmartGroupApply })
394
434
  </div>
395
435
 
396
436
  <!-- Flat View (when no groups) -->
397
- <div v-if="!groupingEnabled" class="mint-sample-selector__flat">
437
+ <div v-if="!isPlaceholderState && !groupingEnabled" class="mint-sample-selector__flat">
398
438
  <!-- Search -->
399
439
  <div class="mint-sample-selector__search">
400
440
  <svg class="mint-sample-selector__search-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -427,7 +467,7 @@ defineExpose({ handleSmartGroupApply })
427
467
  <span class="mint-sample-selector__flat-name">{{ sample }}</span>
428
468
  </div>
429
469
 
430
- <div v-if="filteredSamples.length === 0 && searchQuery.trim()" class="mint-sample-selector__empty">
470
+ <div v-if="filteredSamples.length === 0 && searchQuery.trim()" class="mint-sample-selector__hint">
431
471
  No samples match "{{ searchQuery }}"
432
472
  </div>
433
473
  </div>
@@ -443,9 +483,8 @@ defineExpose({ handleSmartGroupApply })
443
483
  :design-data="resolvedDesignData"
444
484
  @apply="handleSmartGroupApply"
445
485
  />
486
+
487
+ <!-- Group reorder announcements for screen readers -->
488
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ reorderAnnouncement }}</div>
446
489
  </div>
447
490
  </template>
448
-
449
- <style>
450
- @import '../styles/components/sample-selector.css';
451
- </style>
@@ -54,6 +54,18 @@ function onHeaderDrop(event: DragEvent) {
54
54
  if (dragKind.value === null) return
55
55
  props.ctx.onGroupDrop(dragName.value, dragKind.value, event)
56
56
  }
57
+
58
+ /** Enter/Space expand the node; Alt+ArrowUp/Down reorder it among its siblings. */
59
+ function onHeaderKeydown(event: KeyboardEvent) {
60
+ if (event.altKey) {
61
+ if (dragKind.value === null) return
62
+ props.ctx.onGroupReorderKeydown(dragName.value, dragKind.value, event)
63
+ return
64
+ }
65
+ if (event.key !== 'Enter' && event.key !== ' ') return
66
+ event.preventDefault()
67
+ props.ctx.toggleExpanded(props.node.key)
68
+ }
57
69
  </script>
58
70
 
59
71
  <template>
@@ -81,7 +93,14 @@ function onHeaderDrop(event: DragEvent) {
81
93
  reorderEdge === 'after' ? 'mint-sample-selector__header--drag-over-after' : '',
82
94
  ]"
83
95
  :draggable="dragKind !== null"
96
+ role="button"
97
+ tabindex="0"
98
+ :aria-expanded="expanded"
99
+ :aria-label="dragKind !== null
100
+ ? `${node.label}. Press Alt with the up or down arrow keys to reorder.`
101
+ : node.label"
84
102
  @click="ctx.toggleExpanded(node.key)"
103
+ @keydown="onHeaderKeydown"
85
104
  @dragstart="onHeaderDragStart"
86
105
  @dragend="ctx.onGroupDragEnd"
87
106
  @dragover="onHeaderDragOver"
@@ -86,6 +86,8 @@ const mockBlockedSlots: ScheduleBlockedSlot[] = [
86
86
 
87
87
  function initState() {
88
88
  return {
89
+ loading: false,
90
+ error: '',
89
91
  modelValue: today,
90
92
  view: 'week' as const,
91
93
  events: mockEvents,
@@ -106,6 +108,8 @@ function initState() {
106
108
  <template #default="{ state }">
107
109
  <div style="padding: 1rem; height: 700px;">
108
110
  <ScheduleCalendar
111
+ :loading="state.loading"
112
+ :error="state.error || null"
109
113
  v-model="state.modelValue"
110
114
  :view="state.view"
111
115
  :events="state.events"
@@ -123,6 +127,8 @@ function initState() {
123
127
  </div>
124
128
  </template>
125
129
  <template #controls="{ state }">
130
+ <HstCheckbox v-model="state.loading" title="Loading" />
131
+ <HstText v-model="state.error" title="Error Message" />
126
132
  <HstSelect
127
133
  v-model="state.view"
128
134
  title="View"
@@ -7,11 +7,13 @@ import type {
7
7
  ScheduleBlockedSlot,
8
8
  } from '../types/components'
9
9
  import { useScheduleDrag } from '../composables/useScheduleDrag'
10
+ import { useReorderAnnouncer } from '../composables/useListReorder'
10
11
  import {
11
12
  SCHEDULE_SLOT_HEIGHT,
12
13
  parseScheduleModelDate,
13
14
  useScheduleCalendarLayout,
14
15
  } from '../composables/useScheduleCalendarLayout'
16
+ import DataStateInternal from './internal/DataStateInternal.vue'
15
17
 
16
18
  interface Props {
17
19
  modelValue?: Date | string
@@ -28,6 +30,19 @@ interface Props {
28
30
  showNavigation?: boolean
29
31
  statusColors?: Record<string, string>
30
32
  locale?: string
33
+ /** Replace the calendar grid with a loading placeholder. */
34
+ loading?: boolean
35
+ /**
36
+ * Error message. When set, the calendar grid is replaced by an error state.
37
+ * `null`/`undefined` renders normally.
38
+ */
39
+ error?: string | null
40
+ /**
41
+ * Opt-in empty-state headline. An empty grid is meaningful on a calendar, so
42
+ * the empty state only replaces it when this message is supplied and there
43
+ * are no events.
44
+ */
45
+ emptyMessage?: string
31
46
  }
32
47
 
33
48
  const props = withDefaults(defineProps<Props>(), {
@@ -43,6 +58,8 @@ const props = withDefaults(defineProps<Props>(), {
43
58
  showViewToggle: true,
44
59
  showNavigation: true,
45
60
  locale: 'en-US',
61
+ loading: false,
62
+ error: null,
46
63
  })
47
64
 
48
65
  const emit = defineEmits<{
@@ -57,6 +74,11 @@ const emit = defineEmits<{
57
74
 
58
75
  const SLOT_HEIGHT = SCHEDULE_SLOT_HEIGHT
59
76
  const currentView = ref<ScheduleView>(props.view)
77
+
78
+ /** Empty state is opt-in: it needs an `emptyMessage` and an event-free range. */
79
+ const showEmptyState = computed(() =>
80
+ Boolean(props.emptyMessage) && props.events.length === 0,
81
+ )
60
82
  const currentDate = ref<Date>(parseScheduleModelDate(props.modelValue))
61
83
  const nowTimer = ref<ReturnType<typeof setInterval>>()
62
84
  const now = ref(new Date())
@@ -76,7 +98,9 @@ const weekStartsOnRef = computed(() => props.weekStartsOn)
76
98
  const localeRef = computed(() => props.locale)
77
99
  const showNowIndicatorRef = computed(() => props.showNowIndicator)
78
100
 
79
- const { isDragging, ghost, startCreate, startMove, startResize } = useScheduleDrag({
101
+ const { announcement, announce, announcerStyle } = useReorderAnnouncer()
102
+
103
+ const { isDragging, ghost, startCreate, startMove, startResize, nudgeEvent } = useScheduleDrag({
80
104
  slotDuration: slotDurationRef,
81
105
  dayStartHour: dayStartRef,
82
106
  dayEndHour: dayEndRef,
@@ -180,6 +204,35 @@ function onResizePointerDown(event: ScheduleEvent, edge: 'top' | 'bottom', dayIn
180
204
  startResize(event, edge, e.clientY, dayIndex)
181
205
  }
182
206
 
207
+ /**
208
+ * Keyboard alternative to dragging an event: Alt+ArrowUp/Down move it by one
209
+ * slot, Shift+Alt+ArrowUp/Down shorten or lengthen it, Enter/Space open it.
210
+ */
211
+ function onEventKeydown(event: ScheduleEvent, e: KeyboardEvent) {
212
+ if (e.key === 'Enter' || e.key === ' ') {
213
+ e.preventDefault()
214
+ emit('event-click', event)
215
+ return
216
+ }
217
+ if (!e.altKey) return
218
+ const direction = e.key === 'ArrowUp' ? -1 : e.key === 'ArrowDown' ? 1 : 0
219
+ if (direction === 0) return
220
+
221
+ e.preventDefault()
222
+ const mode = e.shiftKey ? 'resize' : 'move'
223
+ const applied = nudgeEvent(event, direction, mode)
224
+ announce(applied
225
+ ? `${event.title} ${mode === 'move' ? 'moved' : 'resized'} to ${formatEventTime(event)}.`
226
+ : `${event.title} cannot move further.`)
227
+ }
228
+
229
+ /** Instructions announced with each event. */
230
+ function eventLabel(event: ScheduleEvent): string {
231
+ const base = `${event.title}, ${formatEventTime(event)}`
232
+ if (props.readonly || event.draggable === false) return base
233
+ return `${base}. Press Alt with the up or down arrow keys to reschedule it.`
234
+ }
235
+
183
236
  function onMonthDayClick(date: Date) {
184
237
  currentDate.value = date
185
238
  emit('update:modelValue', date)
@@ -254,8 +307,27 @@ onUnmounted(() => {
254
307
  </div>
255
308
  </div>
256
309
 
310
+ <!-- Loading / error / empty placeholders replace the grid -->
311
+ <div v-if="error" class="mint-schedule__state">
312
+ <slot name="error" :error="error">
313
+ <DataStateInternal state="error" :title="error" />
314
+ </slot>
315
+ </div>
316
+
317
+ <div v-else-if="loading" class="mint-schedule__state">
318
+ <slot name="loading">
319
+ <DataStateInternal state="loading" loading-label="Loading schedule" />
320
+ </slot>
321
+ </div>
322
+
323
+ <div v-else-if="showEmptyState" class="mint-schedule__state">
324
+ <slot name="empty">
325
+ <DataStateInternal state="empty" :title="emptyMessage" />
326
+ </slot>
327
+ </div>
328
+
257
329
  <!-- Day / Week View -->
258
- <template v-if="currentView === 'day' || currentView === 'week'">
330
+ <template v-else-if="currentView === 'day' || currentView === 'week'">
259
331
  <!-- Day headers -->
260
332
  <div v-if="currentView === 'week'" class="mint-schedule__day-headers">
261
333
  <div class="mint-schedule__day-header-gutter" />
@@ -312,7 +384,11 @@ onUnmounted(() => {
312
384
  :key="event.id"
313
385
  :class="['mint-schedule__event', getStatusClass(event.status)]"
314
386
  :style="getEventStyle(event, day) || undefined"
387
+ role="button"
388
+ tabindex="0"
389
+ :aria-label="eventLabel(event)"
315
390
  @click="onEventClick(event, $event)"
391
+ @keydown="onEventKeydown(event, $event)"
316
392
  @pointerdown="onEventPointerDown(event, dayIdx, $event)"
317
393
  >
318
394
  <slot name="event" :event="event">
@@ -364,7 +440,7 @@ onUnmounted(() => {
364
440
  </template>
365
441
 
366
442
  <!-- Month View -->
367
- <template v-if="currentView === 'month'">
443
+ <template v-else-if="currentView === 'month'">
368
444
  <div class="mint-schedule__month-grid">
369
445
  <!-- Weekday headers -->
370
446
  <div
@@ -406,9 +482,8 @@ onUnmounted(() => {
406
482
  </div>
407
483
  </div>
408
484
  </template>
485
+
486
+ <!-- Reschedule announcements for screen readers -->
487
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ announcement }}</div>
409
488
  </div>
410
489
  </template>
411
-
412
- <style>
413
- @import '../styles/components/schedule-calendar.css';
414
- </style>
@@ -191,7 +191,3 @@ async function copyToClipboard() {
191
191
  </button>
192
192
  </span>
193
193
  </template>
194
-
195
- <style>
196
- @import '../styles/components/scientific-number.css';
197
- </style>
@@ -92,7 +92,3 @@ const cardClasses = computed(() => [
92
92
  </div>
93
93
  </section>
94
94
  </template>
95
-
96
- <style>
97
- @import '../styles/components/section-card.css';
98
- </style>
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
- /** Renders a segmented button group for single-option selection, with simple or solid variants. */
3
- import { computed } from 'vue'
2
+ /** Renders a segmented button group for single-option selection, defaulting to the card variant. */
3
+ import { computed, type ComponentPublicInstance } from 'vue'
4
4
  import type { SegmentedOption, SegmentedOptionInput, SegmentedControlVariant, SegmentedControlSize } from '../types'
5
5
  import { normalizeOptionInput } from '../utils/options'
6
+ import { useRovingFocus } from '../composables/useRovingFocus'
6
7
 
7
8
  interface Props {
8
9
  modelValue: string | number
@@ -15,7 +16,7 @@ interface Props {
15
16
  }
16
17
 
17
18
  const props = withDefaults(defineProps<Props>(), {
18
- variant: 'simple',
19
+ variant: 'card',
19
20
  size: 'md',
20
21
  fullWidth: false,
21
22
  disabled: false,
@@ -42,11 +43,55 @@ function handleSelect(option: SegmentedOption) {
42
43
  emit('update:modelValue', option.value)
43
44
  }
44
45
 
46
+ // Roving tabindex over the radio group: only the checked option is tabbable and
47
+ // Left/Right (plus Home/End) move between the selectable options, matching BaseTabs.
48
+ const optionRefs = new Map<string, HTMLElement>()
49
+
50
+ function optionId(option: SegmentedOption): string {
51
+ return String(option.value)
52
+ }
53
+
54
+ function setOptionRef(id: string, el: Element | ComponentPublicInstance | null) {
55
+ if (el instanceof HTMLElement) {
56
+ optionRefs.set(id, el)
57
+ } else {
58
+ optionRefs.delete(id)
59
+ }
60
+ }
61
+
62
+ const selectableOptions = computed(() =>
63
+ normalizedOptions.value.filter(option => !isSelectionDisabled(option)),
64
+ )
65
+
66
+ /** The one option carrying `tabindex="0"`: the checked one, else the first selectable. */
67
+ const tabbableId = computed(() => {
68
+ const checked = selectableOptions.value.find(option => option.value === props.modelValue)
69
+ const target = checked ?? selectableOptions.value[0]
70
+ return target ? optionId(target) : ''
71
+ })
72
+
73
+ function isTabbable(option: SegmentedOption): boolean {
74
+ return optionId(option) === tabbableId.value
75
+ }
76
+
77
+ const { handleKeydown: handleArrowKeydown } = useRovingFocus({
78
+ ids: () => selectableOptions.value.map(optionId),
79
+ activeId: () => tabbableId.value,
80
+ activate: (id) => {
81
+ const option = selectableOptions.value.find(candidate => optionId(candidate) === id)
82
+ if (option) handleSelect(option)
83
+ },
84
+ getElement: (id) => optionRefs.get(id),
85
+ orientation: 'horizontal',
86
+ })
87
+
45
88
  function handleKeydown(event: KeyboardEvent, option: SegmentedOption) {
46
89
  if (event.key === 'Enter' || event.key === ' ') {
47
90
  event.preventDefault()
48
91
  handleSelect(option)
92
+ return
49
93
  }
94
+ handleArrowKeydown(event)
50
95
  }
51
96
  </script>
52
97
 
@@ -64,9 +109,11 @@ function handleKeydown(event: KeyboardEvent, option: SegmentedOption) {
64
109
  <button
65
110
  v-for="option in normalizedOptions"
66
111
  :key="String(option.value)"
112
+ :ref="(el) => setOptionRef(String(option.value), el)"
67
113
  type="button"
68
114
  role="radio"
69
115
  :aria-checked="modelValue === option.value"
116
+ :tabindex="isTabbable(option) ? 0 : -1"
70
117
  :disabled="isSelectionDisabled(option)"
71
118
  :class="[
72
119
  'mint-segmented-control__option',
@@ -88,7 +135,3 @@ function handleKeydown(event: KeyboardEvent, option: SegmentedOption) {
88
135
  </button>
89
136
  </div>
90
137
  </template>
91
-
92
- <style>
93
- @import '../styles/components/segmented-control.css';
94
- </style>
@@ -203,7 +203,3 @@ function getBaseClass(char: string): string {
203
203
  </div>
204
204
  </div>
205
205
  </template>
206
-
207
- <style>
208
- @import '../styles/components/sequence-input.css';
209
- </style>
@@ -0,0 +1,110 @@
1
+ <script setup lang="ts">
2
+ import SequenceProgressBar from './SequenceProgressBar.vue'
3
+ import type { SequenceProgress } from '../types'
4
+
5
+ const running: SequenceProgress = {
6
+ sequence_name: 'HILIC-neg-2026-09-05',
7
+ current_sample: 37,
8
+ total_samples: 96,
9
+ elapsed_seconds: 4_260,
10
+ estimated_remaining_seconds: 6_780,
11
+ avg_sample_seconds: 115,
12
+ current_sample_name: 'PLASMA_QC_04',
13
+ current_method: 'HILIC_neg_12min',
14
+ }
15
+
16
+ const almostDone: SequenceProgress = {
17
+ ...running,
18
+ current_sample: 94,
19
+ estimated_remaining_seconds: 230,
20
+ }
21
+
22
+ const finished: SequenceProgress = {
23
+ ...running,
24
+ current_sample: 96,
25
+ estimated_remaining_seconds: 0,
26
+ }
27
+
28
+ const justStarted: SequenceProgress = {
29
+ sequence_name: 'RP-pos-batch-7',
30
+ current_sample: 1,
31
+ total_samples: 384,
32
+ }
33
+
34
+ function initState() {
35
+ return {
36
+ current: 37,
37
+ total: 96,
38
+ remaining: 6780,
39
+ compact: false,
40
+ showEta: true,
41
+ showRemaining: true,
42
+ label: 'samples',
43
+ }
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <Story title="Workflow/SequenceProgressBar">
49
+ <Variant title="Playground" :init-state="initState">
50
+ <template #default="{ state }">
51
+ <div style="padding: 2rem; max-width: 600px;">
52
+ <SequenceProgressBar
53
+ :progress="{
54
+ sequence_name: 'HILIC-neg-2026-09-05',
55
+ current_sample: state.current,
56
+ total_samples: state.total,
57
+ estimated_remaining_seconds: state.remaining,
58
+ }"
59
+ :compact="state.compact"
60
+ :label="state.label"
61
+ :show-eta="state.showEta"
62
+ :show-remaining="state.showRemaining"
63
+ />
64
+ </div>
65
+ </template>
66
+
67
+ <template #controls="{ state }">
68
+ <HstNumber v-model="state.current" title="Current sample" />
69
+ <HstNumber v-model="state.total" title="Total samples" />
70
+ <HstNumber v-model="state.remaining" title="Remaining (s)" />
71
+ <HstText v-model="state.label" title="Unit label" />
72
+ <HstCheckbox v-model="state.compact" title="Compact" />
73
+ <HstCheckbox v-model="state.showEta" title="Show ETA" />
74
+ <HstCheckbox v-model="state.showRemaining" title="Show remaining" />
75
+ </template>
76
+ </Variant>
77
+
78
+ <Variant title="Mid-run">
79
+ <div style="padding: 2rem; max-width: 600px;">
80
+ <SequenceProgressBar :progress="running" />
81
+ </div>
82
+ </Variant>
83
+
84
+ <Variant title="Compact (no footer)">
85
+ <!-- Compact drops the remaining/ETA row for dense instrument tables. -->
86
+ <div style="padding: 2rem; max-width: 600px;">
87
+ <SequenceProgressBar :progress="running" compact />
88
+ </div>
89
+ </Variant>
90
+
91
+ <Variant title="Nearly finished">
92
+ <div style="padding: 2rem; max-width: 600px;">
93
+ <SequenceProgressBar :progress="almostDone" />
94
+ </div>
95
+ </Variant>
96
+
97
+ <Variant title="Complete">
98
+ <div style="padding: 2rem; max-width: 600px;">
99
+ <SequenceProgressBar :progress="finished" />
100
+ </div>
101
+ </Variant>
102
+
103
+ <Variant title="Queued — no timing yet">
104
+ <!-- Without timing fields the footer collapses on its own. -->
105
+ <div style="padding: 2rem; max-width: 600px;">
106
+ <SequenceProgressBar :progress="justStarted" label="injections" />
107
+ </div>
108
+ </Variant>
109
+ </Story>
110
+ </template>
@@ -65,7 +65,3 @@ const hasFooter = computed(() => {
65
65
  </div>
66
66
  </div>
67
67
  </template>
68
-
69
- <style>
70
- @import '../styles/components/sequence-progress-bar.css';
71
- </style>
@@ -393,7 +393,3 @@ function canShowForCurrentUser(item: AccessControlled): boolean {
393
393
  </template>
394
394
  </BaseModal>
395
395
  </template>
396
-
397
- <style>
398
- @import '../styles/components/settings-modal.css';
399
- </style>
@@ -68,7 +68,3 @@ const classes = computed(() => {
68
68
  <template>
69
69
  <div :class="classes" :style="style" />
70
70
  </template>
71
-
72
- <style>
73
- @import '../styles/components/skeleton.css';
74
- </style>
@@ -144,8 +144,13 @@ function onDrop(event: DragEvent) {
144
144
  // CSV action menu — reuses the SDK's dropdown state (outside-click / Escape
145
145
  // close) but renders a compact action menu in the .fr-* styling, since the
146
146
  // items are actions (upload / download), not a persistent value selection.
147
- const { isOpen: csvMenuOpen, rootRef: csvMenuRoot, close: closeCsvMenu, toggle: toggleCsvMenu } =
148
- useDropdownState()
147
+ const {
148
+ isOpen: csvMenuOpen,
149
+ rootRef: csvMenuRoot,
150
+ triggerRef: csvMenuTrigger,
151
+ close: closeCsvMenu,
152
+ toggle: toggleCsvMenu,
153
+ } = useDropdownState()
149
154
 
150
155
  function chooseUpload() {
151
156
  closeCsvMenu()
@@ -294,6 +299,7 @@ function onApply() {
294
299
  <div class="sg-head__spacer" />
295
300
  <div ref="csvMenuRoot" class="fr-csv">
296
301
  <button
302
+ ref="csvMenuTrigger"
297
303
  type="button"
298
304
  class="fr-upload"
299
305
  aria-haspopup="menu"
@@ -493,7 +499,3 @@ function onApply() {
493
499
  </div>
494
500
  </div>
495
501
  </template>
496
-
497
- <style>
498
- @import '../styles/components/smart-group.css';
499
- </style>
@@ -392,7 +392,3 @@ function onDone() {
392
392
  </div>
393
393
  </div>
394
394
  </template>
395
-
396
- <style>
397
- @import '../styles/components/smart-group.css';
398
- </style>
@@ -34,7 +34,3 @@ const dotStyle = computed(() =>
34
34
  <span v-if="label" class="mint-status__label">{{ label }}</span>
35
35
  </span>
36
36
  </template>
37
-
38
- <style>
39
- @import '../styles/components/status-indicator.css';
40
- </style>