@morscherlab/mint-sdk 1.0.0-alpha.2

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 (491) hide show
  1. package/README.md +326 -0
  2. package/dist/__stories__/experiment-helpers.d.ts +25 -0
  3. package/dist/__tests__/components/AppLayout.test.d.ts +1 -0
  4. package/dist/__tests__/components/AppSidebar.test.d.ts +1 -0
  5. package/dist/__tests__/components/AppTopBar.test.d.ts +1 -0
  6. package/dist/__tests__/components/BaseInput.test.d.ts +1 -0
  7. package/dist/__tests__/components/BasePill.test.d.ts +1 -0
  8. package/dist/__tests__/components/Calendar.test.d.ts +1 -0
  9. package/dist/__tests__/components/CollapsibleCard.test.d.ts +1 -0
  10. package/dist/__tests__/components/DataFrame.test.d.ts +1 -0
  11. package/dist/__tests__/components/DropdownButton.test.d.ts +1 -0
  12. package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +1 -0
  13. package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useAuth.test.d.ts +1 -0
  15. package/dist/__tests__/composables/useAutoGroup.test.d.ts +1 -0
  16. package/dist/__tests__/composables/useExperimentData.test.d.ts +13 -0
  17. package/dist/__tests__/composables/useExperimentSave.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useForm.test.d.ts +1 -0
  19. package/dist/__tests__/composables/useFormBuilder.test.d.ts +1 -0
  20. package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
  21. package/dist/__tests__/composables/usePluginApi.test.d.ts +13 -0
  22. package/dist/__tests__/composables/usePluginConfig.test.d.ts +14 -0
  23. package/dist/__tests__/utils/color.test.d.ts +1 -0
  24. package/dist/auth-BYmxZdJl.js +297 -0
  25. package/dist/auth-BYmxZdJl.js.map +1 -0
  26. package/dist/components/AlertBox.vue.d.ts +34 -0
  27. package/dist/components/AppAvatarMenu.vue.d.ts +58 -0
  28. package/dist/components/AppContainer.vue.d.ts +28 -0
  29. package/dist/components/AppLayout.vue.d.ts +31 -0
  30. package/dist/components/AppPageSelector.vue.d.ts +43 -0
  31. package/dist/components/AppPillNav.vue.d.ts +11 -0
  32. package/dist/components/AppPluginSwitcher.vue.d.ts +38 -0
  33. package/dist/components/AppSidebar.vue.d.ts +47 -0
  34. package/dist/components/AppTopBar.vue.d.ts +111 -0
  35. package/dist/components/AuditTrail.vue.d.ts +38 -0
  36. package/dist/components/AutoGroupModal.vue.d.ts +124 -0
  37. package/dist/components/Avatar.vue.d.ts +14 -0
  38. package/dist/components/BaseButton.vue.d.ts +37 -0
  39. package/dist/components/BaseCheckbox.vue.d.ts +17 -0
  40. package/dist/components/BaseInput.vue.d.ts +34 -0
  41. package/dist/components/BaseModal.vue.d.ts +46 -0
  42. package/dist/components/BasePill.vue.d.ts +57 -0
  43. package/dist/components/BaseRadioGroup.vue.d.ts +21 -0
  44. package/dist/components/BaseSelect.vue.d.ts +20 -0
  45. package/dist/components/BaseSlider.vue.d.ts +22 -0
  46. package/dist/components/BaseTabs.vue.d.ts +14 -0
  47. package/dist/components/BaseTextarea.vue.d.ts +30 -0
  48. package/dist/components/BaseToggle.vue.d.ts +19 -0
  49. package/dist/components/BatchProgressList.vue.d.ts +43 -0
  50. package/dist/components/Breadcrumb.vue.d.ts +33 -0
  51. package/dist/components/Calendar.vue.d.ts +107 -0
  52. package/dist/components/ChartContainer.vue.d.ts +31 -0
  53. package/dist/components/ChemicalFormula.vue.d.ts +8 -0
  54. package/dist/components/CollapsibleCard.vue.d.ts +41 -0
  55. package/dist/components/ColorSlider.vue.d.ts +34 -0
  56. package/dist/components/ConcentrationInput.vue.d.ts +25 -0
  57. package/dist/components/ConfirmDialog.vue.d.ts +42 -0
  58. package/dist/components/DataFrame.vue.d.ts +107 -0
  59. package/dist/components/DatePicker.vue.d.ts +25 -0
  60. package/dist/components/DateTimePicker.vue.d.ts +30 -0
  61. package/dist/components/Divider.vue.d.ts +14 -0
  62. package/dist/components/DoseCalculator.vue.d.ts +19 -0
  63. package/dist/components/DropdownButton.vue.d.ts +47 -0
  64. package/dist/components/EmptyState.vue.d.ts +36 -0
  65. package/dist/components/ExperimentCodeBadge.vue.d.ts +14 -0
  66. package/dist/components/ExperimentDataViewer.vue.d.ts +29 -0
  67. package/dist/components/ExperimentPopover.vue.d.ts +32 -0
  68. package/dist/components/ExperimentSelectorModal.vue.d.ts +28 -0
  69. package/dist/components/ExperimentTimeline.vue.d.ts +44 -0
  70. package/dist/components/FileUploader.vue.d.ts +40 -0
  71. package/dist/components/FitPanel.vue.d.ts +46 -0
  72. package/dist/components/FormActions.vue.d.ts +33 -0
  73. package/dist/components/FormBuilder.vue.d.ts +287 -0
  74. package/dist/components/FormField.vue.d.ts +28 -0
  75. package/dist/components/FormFieldRenderer.vue.d.ts +31 -0
  76. package/dist/components/FormSection.vue.d.ts +43 -0
  77. package/dist/components/FormulaInput.vue.d.ts +25 -0
  78. package/dist/components/GroupAssigner.vue.d.ts +25 -0
  79. package/dist/components/GroupingModal.vue.d.ts +12 -0
  80. package/dist/components/IconButton.vue.d.ts +34 -0
  81. package/dist/components/LoadingSpinner.vue.d.ts +12 -0
  82. package/dist/components/MoleculeInput.vue.d.ts +27 -0
  83. package/dist/components/MultiSelect.vue.d.ts +19 -0
  84. package/dist/components/NumberInput.vue.d.ts +22 -0
  85. package/dist/components/PlateMapEditor.vue.d.ts +50 -0
  86. package/dist/components/ProgressBar.vue.d.ts +23 -0
  87. package/dist/components/ProtocolStepEditor.vue.d.ts +24 -0
  88. package/dist/components/RackEditor.vue.d.ts +40 -0
  89. package/dist/components/ReagentEditor.vue.d.ts +30 -0
  90. package/dist/components/ReagentList.vue.d.ts +32 -0
  91. package/dist/components/ResourceCard.vue.d.ts +50 -0
  92. package/dist/components/SampleHierarchyTree.vue.d.ts +26 -0
  93. package/dist/components/SampleLegend.vue.d.ts +32 -0
  94. package/dist/components/SampleSelector.vue.d.ts +29 -0
  95. package/dist/components/ScheduleCalendar.vue.d.ts +110 -0
  96. package/dist/components/ScientificNumber.vue.d.ts +14 -0
  97. package/dist/components/SegmentedControl.vue.d.ts +20 -0
  98. package/dist/components/SequenceInput.vue.d.ts +54 -0
  99. package/dist/components/SettingsButton.vue.d.ts +30 -0
  100. package/dist/components/SettingsModal.vue.d.ts +36 -0
  101. package/dist/components/Skeleton.vue.d.ts +11 -0
  102. package/dist/components/StatusIndicator.vue.d.ts +13 -0
  103. package/dist/components/StepWizard.vue.d.ts +65 -0
  104. package/dist/components/TagsInput.vue.d.ts +39 -0
  105. package/dist/components/ThemeToggle.vue.d.ts +7 -0
  106. package/dist/components/TimePicker.vue.d.ts +29 -0
  107. package/dist/components/TimeRangeInput.vue.d.ts +27 -0
  108. package/dist/components/ToastNotification.vue.d.ts +2 -0
  109. package/dist/components/Tooltip.vue.d.ts +35 -0
  110. package/dist/components/UnitInput.vue.d.ts +39 -0
  111. package/dist/components/WellEditPopup.vue.d.ts +25 -0
  112. package/dist/components/WellPlate.vue.d.ts +73 -0
  113. package/dist/components/index.d.ts +87 -0
  114. package/dist/components/index.js +3 -0
  115. package/dist/components-CKf-UpGi.js +15089 -0
  116. package/dist/components-CKf-UpGi.js.map +1 -0
  117. package/dist/composables/experiment-utils.d.ts +8 -0
  118. package/dist/composables/formBuilderRegistry.d.ts +13 -0
  119. package/dist/composables/index.d.ts +28 -0
  120. package/dist/composables/index.js +3 -0
  121. package/dist/composables/useApi.d.ts +20 -0
  122. package/dist/composables/useAppExperiment.d.ts +37 -0
  123. package/dist/composables/useAsync.d.ts +128 -0
  124. package/dist/composables/useAuth.d.ts +47 -0
  125. package/dist/composables/useAutoGroup.d.ts +106 -0
  126. package/dist/composables/useChemicalFormula.d.ts +21 -0
  127. package/dist/composables/useConcentrationUnits.d.ts +29 -0
  128. package/dist/composables/useDoseCalculator.d.ts +58 -0
  129. package/dist/composables/useExperimentData.d.ts +18 -0
  130. package/dist/composables/useExperimentSave.d.ts +36 -0
  131. package/dist/composables/useExperimentSelector.d.ts +30 -0
  132. package/dist/composables/useForm.d.ts +92 -0
  133. package/dist/composables/useFormBuilder.d.ts +24 -0
  134. package/dist/composables/usePasskey.d.ts +10 -0
  135. package/dist/composables/usePlatformContext.d.ts +131 -0
  136. package/dist/composables/usePluginApi.d.ts +29 -0
  137. package/dist/composables/usePluginConfig.d.ts +13 -0
  138. package/dist/composables/useProtocolTemplates.d.ts +44 -0
  139. package/dist/composables/useRackEditor.d.ts +31 -0
  140. package/dist/composables/useReagentSeries.d.ts +23 -0
  141. package/dist/composables/useScheduleDrag.d.ts +78 -0
  142. package/dist/composables/useSequenceUtils.d.ts +14 -0
  143. package/dist/composables/useTheme.d.ts +8 -0
  144. package/dist/composables/useTimeUtils.d.ts +29 -0
  145. package/dist/composables/useToast.d.ts +22 -0
  146. package/dist/composables/useWellPlateEditor.d.ts +33 -0
  147. package/dist/composables-D0QfFzq1.js +805 -0
  148. package/dist/composables-D0QfFzq1.js.map +1 -0
  149. package/dist/histoire.setup.d.ts +1 -0
  150. package/dist/index.d.ts +6 -0
  151. package/dist/index.js +7 -0
  152. package/dist/install.d.ts +16 -0
  153. package/dist/install.js +23 -0
  154. package/dist/install.js.map +1 -0
  155. package/dist/stores/auth.d.ts +146 -0
  156. package/dist/stores/index.d.ts +2 -0
  157. package/dist/stores/index.js +2 -0
  158. package/dist/stores/settings.d.ts +75 -0
  159. package/dist/styles.css +29728 -0
  160. package/dist/tailwind.preset.d.ts +58 -0
  161. package/dist/tailwind.preset.js +66 -0
  162. package/dist/tailwind.preset.js.map +1 -0
  163. package/dist/types/auth.d.ts +42 -0
  164. package/dist/types/auto-group.d.ts +34 -0
  165. package/dist/types/components.d.ts +528 -0
  166. package/dist/types/form-builder.d.ts +167 -0
  167. package/dist/types/index.d.ts +5 -0
  168. package/dist/types/index.js +0 -0
  169. package/dist/types/platform.d.ts +75 -0
  170. package/dist/useScheduleDrag-DAJueTbK.js +7181 -0
  171. package/dist/useScheduleDrag-DAJueTbK.js.map +1 -0
  172. package/dist/utils/color.d.ts +24 -0
  173. package/package.json +114 -0
  174. package/src/__stories__/experiment-helpers.ts +83 -0
  175. package/src/__tests__/components/AppLayout.test.ts +163 -0
  176. package/src/__tests__/components/AppSidebar.test.ts +292 -0
  177. package/src/__tests__/components/AppTopBar.test.ts +683 -0
  178. package/src/__tests__/components/BaseInput.test.ts +99 -0
  179. package/src/__tests__/components/BasePill.test.ts +291 -0
  180. package/src/__tests__/components/Calendar.test.ts +566 -0
  181. package/src/__tests__/components/CollapsibleCard.test.ts +524 -0
  182. package/src/__tests__/components/DataFrame.test.ts +767 -0
  183. package/src/__tests__/components/DropdownButton.test.ts +471 -0
  184. package/src/__tests__/composables/formBuilderRegistry.test.ts +187 -0
  185. package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
  186. package/src/__tests__/composables/useAuth.test.ts +188 -0
  187. package/src/__tests__/composables/useAutoGroup.test.ts +860 -0
  188. package/src/__tests__/composables/useExperimentData.test.ts +127 -0
  189. package/src/__tests__/composables/useExperimentSave.test.ts +347 -0
  190. package/src/__tests__/composables/useForm.test.ts +205 -0
  191. package/src/__tests__/composables/useFormBuilder.test.ts +917 -0
  192. package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
  193. package/src/__tests__/composables/usePluginApi.test.ts +81 -0
  194. package/src/__tests__/composables/usePluginConfig.test.ts +176 -0
  195. package/src/__tests__/utils/color.test.ts +96 -0
  196. package/src/components/AlertBox.story.vue +204 -0
  197. package/src/components/AlertBox.vue +88 -0
  198. package/src/components/AppAvatarMenu.story.vue +155 -0
  199. package/src/components/AppAvatarMenu.vue +184 -0
  200. package/src/components/AppContainer.story.vue +104 -0
  201. package/src/components/AppContainer.vue +34 -0
  202. package/src/components/AppLayout.story.vue +292 -0
  203. package/src/components/AppLayout.vue +75 -0
  204. package/src/components/AppPageSelector.vue +159 -0
  205. package/src/components/AppPillNav.vue +66 -0
  206. package/src/components/AppPluginSwitcher.vue +241 -0
  207. package/src/components/AppSidebar.story.vue +309 -0
  208. package/src/components/AppSidebar.vue +119 -0
  209. package/src/components/AppTopBar.story.vue +304 -0
  210. package/src/components/AppTopBar.vue +661 -0
  211. package/src/components/AuditTrail.story.vue +163 -0
  212. package/src/components/AuditTrail.vue +151 -0
  213. package/src/components/AutoGroupModal.story.vue +273 -0
  214. package/src/components/AutoGroupModal.vue +566 -0
  215. package/src/components/Avatar.story.vue +115 -0
  216. package/src/components/Avatar.vue +79 -0
  217. package/src/components/BaseButton.story.vue +96 -0
  218. package/src/components/BaseButton.vue +73 -0
  219. package/src/components/BaseCheckbox.story.vue +73 -0
  220. package/src/components/BaseCheckbox.vue +69 -0
  221. package/src/components/BaseInput.story.vue +98 -0
  222. package/src/components/BaseInput.vue +74 -0
  223. package/src/components/BaseModal.story.vue +237 -0
  224. package/src/components/BaseModal.vue +182 -0
  225. package/src/components/BasePill.story.vue +142 -0
  226. package/src/components/BasePill.vue +89 -0
  227. package/src/components/BaseRadioGroup.story.vue +145 -0
  228. package/src/components/BaseRadioGroup.vue +124 -0
  229. package/src/components/BaseSelect.story.vue +120 -0
  230. package/src/components/BaseSelect.vue +71 -0
  231. package/src/components/BaseSlider.story.vue +122 -0
  232. package/src/components/BaseSlider.vue +126 -0
  233. package/src/components/BaseTabs.story.vue +127 -0
  234. package/src/components/BaseTabs.vue +59 -0
  235. package/src/components/BaseTextarea.story.vue +91 -0
  236. package/src/components/BaseTextarea.vue +62 -0
  237. package/src/components/BaseToggle.story.vue +81 -0
  238. package/src/components/BaseToggle.vue +76 -0
  239. package/src/components/BatchProgressList.story.vue +92 -0
  240. package/src/components/BatchProgressList.vue +184 -0
  241. package/src/components/Breadcrumb.story.vue +106 -0
  242. package/src/components/Breadcrumb.vue +75 -0
  243. package/src/components/Calendar.story.vue +106 -0
  244. package/src/components/Calendar.vue +363 -0
  245. package/src/components/ChartContainer.story.vue +113 -0
  246. package/src/components/ChartContainer.vue +64 -0
  247. package/src/components/ChemicalFormula.story.vue +102 -0
  248. package/src/components/ChemicalFormula.vue +39 -0
  249. package/src/components/CollapsibleCard.story.vue +135 -0
  250. package/src/components/CollapsibleCard.vue +167 -0
  251. package/src/components/ColorSlider.story.vue +120 -0
  252. package/src/components/ColorSlider.vue +164 -0
  253. package/src/components/ConcentrationInput.story.vue +77 -0
  254. package/src/components/ConcentrationInput.vue +185 -0
  255. package/src/components/ConfirmDialog.story.vue +248 -0
  256. package/src/components/ConfirmDialog.vue +93 -0
  257. package/src/components/DataFrame.story.vue +148 -0
  258. package/src/components/DataFrame.vue +419 -0
  259. package/src/components/DatePicker.story.vue +119 -0
  260. package/src/components/DatePicker.vue +330 -0
  261. package/src/components/DateTimePicker.story.vue +112 -0
  262. package/src/components/DateTimePicker.vue +392 -0
  263. package/src/components/Divider.story.vue +80 -0
  264. package/src/components/Divider.vue +49 -0
  265. package/src/components/DoseCalculator.story.vue +68 -0
  266. package/src/components/DoseCalculator.vue +476 -0
  267. package/src/components/DropdownButton.story.vue +102 -0
  268. package/src/components/DropdownButton.vue +181 -0
  269. package/src/components/EmptyState.story.vue +135 -0
  270. package/src/components/EmptyState.vue +69 -0
  271. package/src/components/ExperimentCodeBadge.story.vue +77 -0
  272. package/src/components/ExperimentCodeBadge.vue +64 -0
  273. package/src/components/ExperimentDataViewer.story.vue +174 -0
  274. package/src/components/ExperimentDataViewer.vue +288 -0
  275. package/src/components/ExperimentPopover.story.vue +384 -0
  276. package/src/components/ExperimentPopover.vue +241 -0
  277. package/src/components/ExperimentSelectorModal.story.vue +391 -0
  278. package/src/components/ExperimentSelectorModal.vue +387 -0
  279. package/src/components/ExperimentTimeline.story.vue +161 -0
  280. package/src/components/ExperimentTimeline.vue +382 -0
  281. package/src/components/FileUploader.story.vue +107 -0
  282. package/src/components/FileUploader.vue +386 -0
  283. package/src/components/FitPanel.story.vue +125 -0
  284. package/src/components/FitPanel.vue +120 -0
  285. package/src/components/FormActions.vue +92 -0
  286. package/src/components/FormBuilder.vue +214 -0
  287. package/src/components/FormField.story.vue +132 -0
  288. package/src/components/FormField.vue +59 -0
  289. package/src/components/FormFieldRenderer.vue +58 -0
  290. package/src/components/FormSection.vue +90 -0
  291. package/src/components/FormulaInput.story.vue +96 -0
  292. package/src/components/FormulaInput.vue +125 -0
  293. package/src/components/GroupAssigner.story.vue +83 -0
  294. package/src/components/GroupAssigner.vue +284 -0
  295. package/src/components/GroupingModal.story.vue +52 -0
  296. package/src/components/GroupingModal.vue +422 -0
  297. package/src/components/IconButton.story.vue +135 -0
  298. package/src/components/IconButton.vue +73 -0
  299. package/src/components/LoadingSpinner.story.vue +70 -0
  300. package/src/components/LoadingSpinner.vue +50 -0
  301. package/src/components/MoleculeInput.story.vue +66 -0
  302. package/src/components/MoleculeInput.vue +426 -0
  303. package/src/components/MultiSelect.story.vue +132 -0
  304. package/src/components/MultiSelect.vue +118 -0
  305. package/src/components/NumberInput.story.vue +122 -0
  306. package/src/components/NumberInput.vue +160 -0
  307. package/src/components/PlateMapEditor.story.vue +92 -0
  308. package/src/components/PlateMapEditor.vue +513 -0
  309. package/src/components/ProgressBar.story.vue +148 -0
  310. package/src/components/ProgressBar.vue +114 -0
  311. package/src/components/ProtocolStepEditor.story.vue +69 -0
  312. package/src/components/ProtocolStepEditor.vue +522 -0
  313. package/src/components/RackEditor.story.vue +100 -0
  314. package/src/components/RackEditor.vue +371 -0
  315. package/src/components/ReagentEditor.story.vue +153 -0
  316. package/src/components/ReagentEditor.vue +418 -0
  317. package/src/components/ReagentList.story.vue +137 -0
  318. package/src/components/ReagentList.vue +463 -0
  319. package/src/components/ResourceCard.story.vue +150 -0
  320. package/src/components/ResourceCard.vue +161 -0
  321. package/src/components/SampleHierarchyTree.story.vue +161 -0
  322. package/src/components/SampleHierarchyTree.vue +256 -0
  323. package/src/components/SampleLegend.story.vue +91 -0
  324. package/src/components/SampleLegend.vue +119 -0
  325. package/src/components/SampleSelector.story.vue +111 -0
  326. package/src/components/SampleSelector.vue +1033 -0
  327. package/src/components/ScheduleCalendar.story.vue +195 -0
  328. package/src/components/ScheduleCalendar.vue +569 -0
  329. package/src/components/ScientificNumber.story.vue +127 -0
  330. package/src/components/ScientificNumber.vue +197 -0
  331. package/src/components/SegmentedControl.story.vue +132 -0
  332. package/src/components/SegmentedControl.vue +79 -0
  333. package/src/components/SequenceInput.story.vue +119 -0
  334. package/src/components/SequenceInput.vue +209 -0
  335. package/src/components/SettingsButton.story.vue +58 -0
  336. package/src/components/SettingsButton.vue +76 -0
  337. package/src/components/SettingsModal.story.vue +145 -0
  338. package/src/components/SettingsModal.vue +146 -0
  339. package/src/components/Skeleton.story.vue +141 -0
  340. package/src/components/Skeleton.vue +74 -0
  341. package/src/components/StatusIndicator.story.vue +99 -0
  342. package/src/components/StatusIndicator.vue +40 -0
  343. package/src/components/StepWizard.story.vue +155 -0
  344. package/src/components/StepWizard.vue +223 -0
  345. package/src/components/TagsInput.story.vue +155 -0
  346. package/src/components/TagsInput.vue +265 -0
  347. package/src/components/ThemeToggle.story.vue +36 -0
  348. package/src/components/ThemeToggle.vue +54 -0
  349. package/src/components/TimePicker.story.vue +96 -0
  350. package/src/components/TimePicker.vue +273 -0
  351. package/src/components/TimeRangeInput.story.vue +104 -0
  352. package/src/components/TimeRangeInput.vue +122 -0
  353. package/src/components/ToastNotification.story.vue +157 -0
  354. package/src/components/ToastNotification.vue +62 -0
  355. package/src/components/Tooltip.story.vue +138 -0
  356. package/src/components/Tooltip.vue +119 -0
  357. package/src/components/UnitInput.story.vue +194 -0
  358. package/src/components/UnitInput.vue +213 -0
  359. package/src/components/WellEditPopup.vue +234 -0
  360. package/src/components/WellPlate.story.vue +282 -0
  361. package/src/components/WellPlate.vue +830 -0
  362. package/src/components/index.ts +118 -0
  363. package/src/composables/experiment-utils.ts +57 -0
  364. package/src/composables/formBuilderRegistry.ts +79 -0
  365. package/src/composables/index.ts +140 -0
  366. package/src/composables/useApi.ts +167 -0
  367. package/src/composables/useAppExperiment.ts +159 -0
  368. package/src/composables/useAsync.ts +323 -0
  369. package/src/composables/useAuth.ts +445 -0
  370. package/src/composables/useAutoGroup.ts +641 -0
  371. package/src/composables/useChemicalFormula.ts +275 -0
  372. package/src/composables/useConcentrationUnits.ts +246 -0
  373. package/src/composables/useDoseCalculator.ts +370 -0
  374. package/src/composables/useExperimentData.ts +86 -0
  375. package/src/composables/useExperimentSave.ts +192 -0
  376. package/src/composables/useExperimentSelector.ts +292 -0
  377. package/src/composables/useForm.ts +416 -0
  378. package/src/composables/useFormBuilder.ts +383 -0
  379. package/src/composables/usePasskey.ts +216 -0
  380. package/src/composables/usePlatformContext.ts +299 -0
  381. package/src/composables/usePluginApi.ts +39 -0
  382. package/src/composables/usePluginConfig.ts +93 -0
  383. package/src/composables/useProtocolTemplates.ts +518 -0
  384. package/src/composables/useRackEditor.ts +222 -0
  385. package/src/composables/useReagentSeries.ts +91 -0
  386. package/src/composables/useScheduleDrag.ts +245 -0
  387. package/src/composables/useSequenceUtils.ts +105 -0
  388. package/src/composables/useTheme.ts +58 -0
  389. package/src/composables/useTimeUtils.ts +131 -0
  390. package/src/composables/useToast.ts +40 -0
  391. package/src/composables/useWellPlateEditor.ts +421 -0
  392. package/src/histoire.setup.ts +17 -0
  393. package/src/index.ts +367 -0
  394. package/src/install.ts +32 -0
  395. package/src/stores/auth.ts +152 -0
  396. package/src/stores/index.ts +2 -0
  397. package/src/stores/settings.ts +218 -0
  398. package/src/styles/components/alert-box.css +150 -0
  399. package/src/styles/components/app-avatar-menu.css +155 -0
  400. package/src/styles/components/app-container.css +33 -0
  401. package/src/styles/components/app-layout.css +98 -0
  402. package/src/styles/components/app-page-selector.css +191 -0
  403. package/src/styles/components/app-pill-nav.css +57 -0
  404. package/src/styles/components/app-plugin-switcher.css +209 -0
  405. package/src/styles/components/app-sidebar.css +145 -0
  406. package/src/styles/components/app-top-bar.css +492 -0
  407. package/src/styles/components/audit-trail.css +143 -0
  408. package/src/styles/components/auto-group-modal.css +644 -0
  409. package/src/styles/components/avatar.css +73 -0
  410. package/src/styles/components/batch-progress-list.css +196 -0
  411. package/src/styles/components/breadcrumb.css +64 -0
  412. package/src/styles/components/button.css +188 -0
  413. package/src/styles/components/calendar.css +192 -0
  414. package/src/styles/components/chart-container.css +69 -0
  415. package/src/styles/components/checkbox.css +123 -0
  416. package/src/styles/components/chemical-formula.css +46 -0
  417. package/src/styles/components/collapsible-card.css +253 -0
  418. package/src/styles/components/color-slider.css +110 -0
  419. package/src/styles/components/concentration-input.css +156 -0
  420. package/src/styles/components/confirm-dialog.css +183 -0
  421. package/src/styles/components/dataframe.css +382 -0
  422. package/src/styles/components/date-picker.css +243 -0
  423. package/src/styles/components/datetime-picker.css +229 -0
  424. package/src/styles/components/divider.css +63 -0
  425. package/src/styles/components/dose-calculator.css +301 -0
  426. package/src/styles/components/dropdown-button.css +280 -0
  427. package/src/styles/components/empty-state.css +151 -0
  428. package/src/styles/components/experiment-code-badge.css +33 -0
  429. package/src/styles/components/experiment-data-viewer.css +138 -0
  430. package/src/styles/components/experiment-popover.css +562 -0
  431. package/src/styles/components/experiment-selector-modal.css +285 -0
  432. package/src/styles/components/experiment-timeline.css +529 -0
  433. package/src/styles/components/file-uploader.css +310 -0
  434. package/src/styles/components/fit-panel.css +67 -0
  435. package/src/styles/components/form-builder.css +69 -0
  436. package/src/styles/components/form-field.css +48 -0
  437. package/src/styles/components/formula-input.css +103 -0
  438. package/src/styles/components/group-assigner.css +200 -0
  439. package/src/styles/components/grouping-modal.css +323 -0
  440. package/src/styles/components/icon-button.css +192 -0
  441. package/src/styles/components/input.css +66 -0
  442. package/src/styles/components/loading-spinner.css +67 -0
  443. package/src/styles/components/modal.css +350 -0
  444. package/src/styles/components/molecule-input.css +186 -0
  445. package/src/styles/components/multi-select.css +131 -0
  446. package/src/styles/components/number-input.css +199 -0
  447. package/src/styles/components/pill.css +188 -0
  448. package/src/styles/components/plate-map-editor.css +464 -0
  449. package/src/styles/components/progress-bar.css +133 -0
  450. package/src/styles/components/protocol-step-editor.css +449 -0
  451. package/src/styles/components/rack-editor.css +265 -0
  452. package/src/styles/components/radio-group.css +240 -0
  453. package/src/styles/components/reagent-editor.css +510 -0
  454. package/src/styles/components/reagent-list.css +407 -0
  455. package/src/styles/components/resource-card.css +360 -0
  456. package/src/styles/components/sample-hierarchy-tree.css +314 -0
  457. package/src/styles/components/sample-legend.css +201 -0
  458. package/src/styles/components/sample-selector.css +751 -0
  459. package/src/styles/components/schedule-calendar.css +478 -0
  460. package/src/styles/components/scientific-number.css +63 -0
  461. package/src/styles/components/segmented-control.css +197 -0
  462. package/src/styles/components/select.css +77 -0
  463. package/src/styles/components/sequence-input.css +184 -0
  464. package/src/styles/components/settings-button.css +94 -0
  465. package/src/styles/components/settings-modal.css +95 -0
  466. package/src/styles/components/skeleton.css +49 -0
  467. package/src/styles/components/slider.css +74 -0
  468. package/src/styles/components/status-indicator.css +66 -0
  469. package/src/styles/components/step-wizard.css +192 -0
  470. package/src/styles/components/tabs.css +95 -0
  471. package/src/styles/components/tags-input.css +195 -0
  472. package/src/styles/components/textarea.css +82 -0
  473. package/src/styles/components/theme-toggle.css +69 -0
  474. package/src/styles/components/time-picker.css +171 -0
  475. package/src/styles/components/time-range-input.css +42 -0
  476. package/src/styles/components/toast.css +91 -0
  477. package/src/styles/components/toggle.css +146 -0
  478. package/src/styles/components/tooltip.css +91 -0
  479. package/src/styles/components/unit-input.css +123 -0
  480. package/src/styles/components/well-edit-popup.css +252 -0
  481. package/src/styles/components/well-plate.css +307 -0
  482. package/src/styles/index.css +87 -0
  483. package/src/styles/variables.css +1117 -0
  484. package/src/tailwind.preset.ts +61 -0
  485. package/src/types/auth.ts +55 -0
  486. package/src/types/auto-group.ts +40 -0
  487. package/src/types/components.ts +710 -0
  488. package/src/types/form-builder.ts +197 -0
  489. package/src/types/index.ts +207 -0
  490. package/src/types/platform.ts +116 -0
  491. package/src/utils/color.ts +96 -0
@@ -0,0 +1,185 @@
1
+ <script setup lang="ts">
2
+ /** Paired numeric + unit input for reagent concentrations (pM–M, mg/mL, etc.) with optional molar-mass conversion hint. */
3
+ import { computed, watch } from 'vue'
4
+ import {
5
+ useConcentrationUnits,
6
+ type ConcentrationValue,
7
+ type ConcentrationUnit,
8
+ } from '../composables/useConcentrationUnits'
9
+
10
+ interface Props {
11
+ modelValue?: ConcentrationValue
12
+ allowedUnits?: ConcentrationUnit[]
13
+ showConversion?: boolean
14
+ molecularWeight?: number
15
+ min?: number
16
+ max?: number
17
+ disabled?: boolean
18
+ error?: boolean
19
+ size?: 'sm' | 'md' | 'lg'
20
+ placeholder?: string
21
+ }
22
+
23
+ const props = withDefaults(defineProps<Props>(), {
24
+ showConversion: true,
25
+ disabled: false,
26
+ error: false,
27
+ size: 'md',
28
+ placeholder: 'Enter value',
29
+ })
30
+
31
+ const emit = defineEmits<{
32
+ 'update:modelValue': [value: ConcentrationValue | undefined]
33
+ }>()
34
+
35
+ const { unitCategories, getConversionHint } = useConcentrationUnits()
36
+
37
+ // Filter categories based on allowedUnits
38
+ const filteredCategories = computed(() => {
39
+ if (!props.allowedUnits || props.allowedUnits.length === 0) {
40
+ return unitCategories.value
41
+ }
42
+ return unitCategories.value
43
+ .map(cat => ({
44
+ label: cat.label,
45
+ units: cat.units.filter(u => props.allowedUnits!.includes(u)),
46
+ }))
47
+ .filter(cat => cat.units.length > 0)
48
+ })
49
+
50
+ // Flatten all available units
51
+ const availableUnits = computed(() => {
52
+ return filteredCategories.value.flatMap(cat => cat.units)
53
+ })
54
+
55
+ // Current value and unit
56
+ const currentValue = computed(() => props.modelValue?.value)
57
+ const currentUnit = computed(() => props.modelValue?.unit || availableUnits.value[0] || 'µM')
58
+
59
+ // Conversion hint
60
+ const conversionHint = computed(() => {
61
+ if (!props.showConversion || !props.modelValue) return null
62
+ return getConversionHint(props.modelValue)
63
+ })
64
+
65
+ function handleValueInput(event: Event) {
66
+ const target = event.target as HTMLInputElement
67
+ const value = target.value === '' ? undefined : Number(target.value)
68
+
69
+ if (value === undefined || isNaN(value)) {
70
+ emit('update:modelValue', undefined)
71
+ return
72
+ }
73
+
74
+ // Apply min/max constraints
75
+ let clampedValue = value
76
+ if (props.min !== undefined && clampedValue < props.min) {
77
+ clampedValue = props.min
78
+ }
79
+ if (props.max !== undefined && clampedValue > props.max) {
80
+ clampedValue = props.max
81
+ }
82
+
83
+ emit('update:modelValue', {
84
+ value: clampedValue,
85
+ unit: currentUnit.value,
86
+ })
87
+ }
88
+
89
+ function handleUnitChange(event: Event) {
90
+ const target = event.target as HTMLSelectElement
91
+ const unit = target.value as ConcentrationUnit
92
+
93
+ emit('update:modelValue', {
94
+ value: currentValue.value ?? 0,
95
+ unit,
96
+ })
97
+ }
98
+
99
+ // Ensure modelValue always has a valid unit
100
+ watch(availableUnits, (units) => {
101
+ if (props.modelValue && !units.includes(props.modelValue.unit)) {
102
+ emit('update:modelValue', {
103
+ value: props.modelValue.value,
104
+ unit: units[0] || 'µM',
105
+ })
106
+ }
107
+ }, { immediate: true })
108
+ </script>
109
+
110
+ <template>
111
+ <div
112
+ :class="[
113
+ 'mld-concentration-input',
114
+ error ? 'mld-concentration-input--error' : '',
115
+ disabled ? 'mld-concentration-input--disabled' : '',
116
+ ]"
117
+ >
118
+ <div :class="['mld-concentration-input__controls', `mld-concentration-input__controls--${size}`]">
119
+ <input
120
+ type="number"
121
+ :value="currentValue"
122
+ :min="min"
123
+ :max="max"
124
+ :disabled="disabled"
125
+ :placeholder="placeholder"
126
+ :class="[
127
+ 'mld-concentration-input__value',
128
+ `mld-concentration-input__value--${size}`,
129
+ disabled ? 'mld-concentration-input__value--disabled' : '',
130
+ ]"
131
+ aria-label="Concentration value"
132
+ @input="handleValueInput"
133
+ />
134
+
135
+ <div class="mld-concentration-input__unit">
136
+ <select
137
+ :value="currentUnit"
138
+ :disabled="disabled"
139
+ :class="[
140
+ 'mld-concentration-input__unit-select',
141
+ `mld-concentration-input__unit-select--${size}`,
142
+ ]"
143
+ aria-label="Concentration unit"
144
+ @change="handleUnitChange"
145
+ >
146
+ <template v-for="category in filteredCategories" :key="category.label">
147
+ <optgroup
148
+ v-if="filteredCategories.length > 1"
149
+ :label="category.label"
150
+ class="mld-concentration-input__unit-group"
151
+ >
152
+ <option
153
+ v-for="unit in category.units"
154
+ :key="unit"
155
+ :value="unit"
156
+ >
157
+ {{ unit }}
158
+ </option>
159
+ </optgroup>
160
+ <template v-else>
161
+ <option
162
+ v-for="unit in category.units"
163
+ :key="unit"
164
+ :value="unit"
165
+ >
166
+ {{ unit }}
167
+ </option>
168
+ </template>
169
+ </template>
170
+ </select>
171
+ </div>
172
+ </div>
173
+
174
+ <div
175
+ v-if="showConversion && conversionHint"
176
+ class="mld-concentration-input__conversion"
177
+ >
178
+ {{ conversionHint }}
179
+ </div>
180
+ </div>
181
+ </template>
182
+
183
+ <style>
184
+ @import '../styles/components/concentration-input.css';
185
+ </style>
@@ -0,0 +1,248 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import ConfirmDialog from './ConfirmDialog.vue'
4
+ import BaseButton from './BaseButton.vue'
5
+ import type { ConfirmVariant } from '../types'
6
+
7
+ const variants: ConfirmVariant[] = ['danger', 'warning', 'info']
8
+
9
+ const dialogOpen = ref(false)
10
+ const dangerOpen = ref(false)
11
+ const warningOpen = ref(false)
12
+ const infoOpen = ref(false)
13
+ const loadingOpen = ref(false)
14
+ const saveOpen = ref(false)
15
+ const uninstallOpen = ref(false)
16
+ const isLoading = ref(false)
17
+ const lastAction = ref<string>('')
18
+
19
+ function log(action: string) {
20
+ lastAction.value = action
21
+ }
22
+
23
+ function handleConfirmLoading() {
24
+ isLoading.value = true
25
+ setTimeout(() => {
26
+ isLoading.value = false
27
+ loadingOpen.value = false
28
+ log('submitted')
29
+ }, 2000)
30
+ }
31
+
32
+ function initPlayground() {
33
+ return {
34
+ title: 'Delete experiment',
35
+ subtitle: 'EXP-2024-001 · Dose-response',
36
+ message: 'This will permanently delete the experiment and all associated data. This action cannot be undone.',
37
+ variant: 'danger' as ConfirmVariant,
38
+ confirmLabel: 'Delete',
39
+ cancelLabel: 'Cancel',
40
+ loading: false,
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <Story title="Layout/ConfirmDialog">
47
+ <!-- Playground — all props wired, BaseButton trigger -->
48
+ <Variant title="Playground" :init-state="initPlayground">
49
+ <template #default="{ state }">
50
+ <div style="padding: 2rem; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem;">
51
+ <BaseButton variant="secondary" @click="dialogOpen = true">Open dialog</BaseButton>
52
+ <div v-if="lastAction" style="font-family: 'Fira Code', monospace; font-size: 0.75rem; color: var(--text-muted);">
53
+ Last event: <code>{{ lastAction }}</code>
54
+ </div>
55
+ <ConfirmDialog
56
+ v-model="dialogOpen"
57
+ :title="state.title"
58
+ :subtitle="state.subtitle"
59
+ :message="state.message"
60
+ :variant="state.variant"
61
+ :confirm-label="state.confirmLabel"
62
+ :cancel-label="state.cancelLabel"
63
+ :loading="state.loading"
64
+ @confirm="() => { dialogOpen = false; log('confirm') }"
65
+ @cancel="log('cancel')"
66
+ />
67
+ </div>
68
+ </template>
69
+
70
+ <template #controls="{ state }">
71
+ <HstText v-model="state.title" title="Title" />
72
+ <HstText v-model="state.subtitle" title="Subtitle (context line)" />
73
+ <HstText v-model="state.message" title="Message" />
74
+ <HstSelect
75
+ v-model="state.variant"
76
+ title="Variant"
77
+ :options="variants.map(v => ({ label: v, value: v }))"
78
+ />
79
+ <HstText v-model="state.confirmLabel" title="Confirm label" />
80
+ <HstText v-model="state.cancelLabel" title="Cancel label" />
81
+ <HstCheckbox v-model="state.loading" title="Loading" />
82
+ </template>
83
+ </Variant>
84
+
85
+ <!-- Plugin uninstall — the canonical refresh-design pattern with subtitle -->
86
+ <Variant title="Plugin uninstall" :init-state="() => ({})">
87
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
88
+ <BaseButton variant="danger" @click="uninstallOpen = true">Uninstall plugin</BaseButton>
89
+ <ConfirmDialog
90
+ v-model="uninstallOpen"
91
+ title="Confirm uninstall"
92
+ subtitle="mld-plugin-metabolomics · v2.4.1"
93
+ message="Removing this plugin will delete its routes from the platform on next restart. Plugin data and registered experiment types will be preserved."
94
+ variant="danger"
95
+ confirm-label="Uninstall"
96
+ @confirm="() => { uninstallOpen = false; log('uninstalled metabolomics') }"
97
+ />
98
+ </div>
99
+ <p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
100
+ The canonical refresh layout: title + subtitle (plugin name · version) sit in the modal header; body holds
101
+ only the explanatory message; red confirm carries the variant intent — no icon needed.
102
+ </p>
103
+ </Variant>
104
+
105
+ <!-- Danger — destructive, the canonical use case -->
106
+ <Variant title="Danger" :init-state="() => ({})">
107
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
108
+ <BaseButton variant="danger" @click="dangerOpen = true">Delete experiment</BaseButton>
109
+ <ConfirmDialog
110
+ v-model="dangerOpen"
111
+ title="Delete Experiment"
112
+ message="Are you sure you want to delete this experiment? All associated data, plates, and analysis results will be permanently removed. This action cannot be undone."
113
+ variant="danger"
114
+ confirm-label="Delete"
115
+ @confirm="() => { dangerOpen = false; log('deleted') }"
116
+ />
117
+ </div>
118
+ </Variant>
119
+
120
+ <!-- Warning — discard unsaved changes -->
121
+ <Variant title="Warning" :init-state="() => ({})">
122
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
123
+ <BaseButton variant="secondary" @click="warningOpen = true">Reset analysis</BaseButton>
124
+ <ConfirmDialog
125
+ v-model="warningOpen"
126
+ title="Reset Analysis"
127
+ message="This will discard all unsaved changes and reset the analysis to its initial state. Do you want to continue?"
128
+ variant="warning"
129
+ confirm-label="Reset"
130
+ @confirm="() => { warningOpen = false; log('reset') }"
131
+ />
132
+ </div>
133
+ </Variant>
134
+
135
+ <!-- Info — positive affirmation (CTA proceeding with an action) -->
136
+ <Variant title="Info" :init-state="() => ({})">
137
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
138
+ <BaseButton variant="primary" @click="infoOpen = true">Export data</BaseButton>
139
+ <ConfirmDialog
140
+ v-model="infoOpen"
141
+ title="Export Data"
142
+ message="This will generate a CSV export of all 96 wells across 3 plates. The download will start automatically."
143
+ variant="info"
144
+ confirm-label="Export"
145
+ @confirm="() => { infoOpen = false; log('exported') }"
146
+ />
147
+ </div>
148
+ </Variant>
149
+
150
+ <!-- Save to Experiment — the actual ExperimentPopover flow -->
151
+ <Variant title="Save to Experiment" :init-state="() => ({})">
152
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
153
+ <BaseButton variant="primary" @click="saveOpen = true">Save to EXP-042</BaseButton>
154
+ <ConfirmDialog
155
+ v-model="saveOpen"
156
+ title="Save to Experiment"
157
+ message="Save current data to DRP Dose-Response Screen · March 2026?"
158
+ variant="info"
159
+ confirm-label="Save"
160
+ @confirm="() => { saveOpen = false; log('saved to EXP-042') }"
161
+ />
162
+ </div>
163
+ <p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
164
+ The exact dialog raised from <code>ExperimentPopover</code> when the user clicks the inline save in the topbar
165
+ with <code>confirmSave: true</code>.
166
+ </p>
167
+ </Variant>
168
+
169
+ <!-- Loading state — confirm button shows spinner, dialog stays open -->
170
+ <Variant title="Loading state" :init-state="() => ({})">
171
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center;">
172
+ <BaseButton variant="primary" @click="loadingOpen = true">Submit results</BaseButton>
173
+ <ConfirmDialog
174
+ v-model="loadingOpen"
175
+ title="Submit Results"
176
+ message="Submit the analysis results to the platform? This may take a moment."
177
+ variant="info"
178
+ confirm-label="Submit"
179
+ :loading="isLoading"
180
+ @confirm="handleConfirmLoading"
181
+ />
182
+ </div>
183
+ <p style="text-align: center; font-size: 0.75rem; color: var(--text-muted); padding: 0 2rem 1rem;">
184
+ Click Submit → confirm button spins for 2s, cancel disables, overlay click/escape blocked while loading.
185
+ </p>
186
+ </Variant>
187
+ </Story>
188
+ </template>
189
+
190
+ <docs lang="md">
191
+ ## ConfirmDialog
192
+
193
+ A compact modal for confirming a decision. Wraps `BaseModal` (inheriting its
194
+ refresh-design container polish: 2-layer shadow, lighter overlay, 15px title
195
+ hierarchy, horizontal divider between header and body).
196
+
197
+ ### Anatomy (refresh layout)
198
+
199
+ ```
200
+ ┌─────────────────────────────────────────────┐
201
+ │ Title × │ ← BaseModal header
202
+ │ Subtitle line (context) │ (title + optional subtitle)
203
+ ├─────────────────────────────────────────────┤
204
+ │ │
205
+ │ The message explains what will happen and │ ← body: just the message
206
+ │ any consequences the user should know. │
207
+ │ │
208
+ ├─────────────────────────────────────────────┤
209
+ │ [ Cancel ] [ Action ] │ ← footer: buttons flush-right
210
+ └─────────────────────────────────────────────┘
211
+ ```
212
+
213
+ - **Title + subtitle** live at the top in `BaseModal`'s header — the subtitle is
214
+ a one-line context string (plugin name · version, experiment code, etc.)
215
+ - **Body** holds only the message. No forced icon sidebar — the variant's intent
216
+ is carried by the confirm button's color
217
+ - **Icon is opt-in**: pass a `#icon` slot only if your message needs an extra
218
+ visual signal. Most confirmations don't.
219
+
220
+ ### Button tactile system
221
+
222
+ The Cancel + Confirm buttons use the **same system as BaseButton**:
223
+
224
+ - Hover: `translateY(-1px)` + `var(--shadow-sm)` over 150ms with `--mint-ease-out-quart`
225
+ - Press: snap to `translateY(0)`, shadow cleared, gradient flattened at 50ms
226
+ - Filled confirm gets the 12% white gradient overlay
227
+ - `prefers-reduced-motion` guarded
228
+
229
+ ### Variant semantics
230
+
231
+ | Variant | Confirm button color | When to use |
232
+ |---|---|---|
233
+ | `danger` | `--mint-error` | Destructive or irreversible actions (delete, uninstall, drop table) |
234
+ | `warning` | `--mint-warning` | Potentially lossy actions (discard unsaved, overwrite config) |
235
+ | `info` | `--color-primary` | Affirmative CTAs (save, submit, export, publish) |
236
+
237
+ **Why `info` uses `--color-primary` not `--mint-info`**: info-as-CTA means
238
+ "proceed with this positive action" — it should match the primary button color,
239
+ not the informational-banner cyan that's reserved for non-action status pills.
240
+
241
+ ### Loading state contract
242
+
243
+ When `loading: true`:
244
+ - Confirm button replaces its label with a spinner, disables hover
245
+ - Cancel button is disabled
246
+ - Overlay click and Escape-to-close are both blocked — the user can't
247
+ accidentally dismiss an in-flight operation
248
+ </docs>
@@ -0,0 +1,93 @@
1
+ <script setup lang="ts">
2
+ /** Confirm/cancel dialog with danger, warning, and info variants; blocks close while loading. */
3
+ import BaseModal from './BaseModal.vue'
4
+
5
+ interface Props {
6
+ modelValue: boolean
7
+ title?: string
8
+ subtitle?: string
9
+ message?: string
10
+ variant?: 'danger' | 'warning' | 'info'
11
+ confirmLabel?: string
12
+ cancelLabel?: string
13
+ loading?: boolean
14
+ }
15
+
16
+ withDefaults(defineProps<Props>(), {
17
+ title: 'Confirm',
18
+ variant: 'danger',
19
+ confirmLabel: 'Confirm',
20
+ cancelLabel: 'Cancel',
21
+ loading: false,
22
+ })
23
+
24
+ const emit = defineEmits<{
25
+ 'update:modelValue': [value: boolean]
26
+ confirm: []
27
+ cancel: []
28
+ }>()
29
+
30
+ function handleCancel() {
31
+ emit('update:modelValue', false)
32
+ emit('cancel')
33
+ }
34
+
35
+ function handleConfirm() {
36
+ emit('confirm')
37
+ }
38
+ </script>
39
+
40
+ <template>
41
+ <BaseModal
42
+ :model-value="modelValue"
43
+ :title="title"
44
+ :subtitle="subtitle"
45
+ size="sm"
46
+ :closable="!loading"
47
+ :close-on-overlay="!loading"
48
+ :close-on-escape="!loading"
49
+ @update:model-value="emit('update:modelValue', $event)"
50
+ >
51
+ <div class="mld-confirm">
52
+ <!-- Icon is now opt-in via slot. Refresh design keeps the body focused on
53
+ the message; variant intent is carried by the confirm button's color. -->
54
+ <div
55
+ v-if="$slots.icon"
56
+ :class="['mld-confirm__icon', `mld-confirm__icon--${variant}`]"
57
+ >
58
+ <slot name="icon" />
59
+ </div>
60
+ <p v-if="message" class="mld-confirm__message">{{ message }}</p>
61
+ <slot />
62
+ </div>
63
+
64
+ <template #footer>
65
+ <div class="mld-confirm__footer">
66
+ <button
67
+ type="button"
68
+ class="mld-confirm__btn-cancel"
69
+ :disabled="loading"
70
+ @click="handleCancel"
71
+ >
72
+ {{ cancelLabel }}
73
+ </button>
74
+ <button
75
+ type="button"
76
+ :class="['mld-confirm__btn-confirm', `mld-confirm__btn-confirm--${variant}`]"
77
+ :disabled="loading"
78
+ @click="handleConfirm"
79
+ >
80
+ <svg v-if="loading" class="mld-confirm__btn-spinner" fill="none" viewBox="0 0 24 24">
81
+ <circle style="opacity: 0.25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
82
+ <path style="opacity: 0.75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
83
+ </svg>
84
+ {{ confirmLabel }}
85
+ </button>
86
+ </div>
87
+ </template>
88
+ </BaseModal>
89
+ </template>
90
+
91
+ <style>
92
+ @import '../styles/components/confirm-dialog.css';
93
+ </style>
@@ -0,0 +1,148 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import DataFrame from './DataFrame.vue'
4
+ import type { DataFrameColumn, PaginationState } from '../types'
5
+
6
+ const columns: DataFrameColumn[] = [
7
+ { key: 'id', label: 'ID', sortable: true, width: 60, align: 'center' },
8
+ { key: 'compound', label: 'Compound', sortable: true },
9
+ { key: 'concentration', label: 'Conc. (uM)', sortable: true, align: 'right' },
10
+ { key: 'response', label: 'Response (%)', sortable: true, align: 'right' },
11
+ { key: 'well', label: 'Well', align: 'center' },
12
+ { key: 'status', label: 'Status' },
13
+ ]
14
+
15
+ const data = [
16
+ { id: 1, compound: 'MINT-2847', concentration: 10.0, response: 95.2, well: 'A1', status: 'Pass' },
17
+ { id: 2, compound: 'MINT-2847', concentration: 3.33, response: 82.1, well: 'A2', status: 'Pass' },
18
+ { id: 3, compound: 'MINT-2847', concentration: 1.11, response: 54.7, well: 'A3', status: 'Pass' },
19
+ { id: 4, compound: 'MINT-2847', concentration: 0.37, response: 23.4, well: 'A4', status: 'Pass' },
20
+ { id: 5, compound: 'MINT-2847', concentration: 0.12, response: 8.9, well: 'A5', status: 'Pass' },
21
+ { id: 6, compound: 'MINT-3192', concentration: 10.0, response: 88.7, well: 'B1', status: 'Pass' },
22
+ { id: 7, compound: 'MINT-3192', concentration: 3.33, response: 71.3, well: 'B2', status: 'Pass' },
23
+ { id: 8, compound: 'MINT-3192', concentration: 1.11, response: 45.2, well: 'B3', status: 'Flagged' },
24
+ { id: 9, compound: 'MINT-3192', concentration: 0.37, response: 18.6, well: 'B4', status: 'Pass' },
25
+ { id: 10, compound: 'MINT-3192', concentration: 0.12, response: 5.1, well: 'B5', status: 'Pass' },
26
+ { id: 11, compound: 'Vehicle', concentration: 0, response: 2.3, well: 'C1', status: 'Pass' },
27
+ { id: 12, compound: 'Vehicle', concentration: 0, response: 1.8, well: 'C2', status: 'Pass' },
28
+ ]
29
+
30
+ const selectedKeys = ref<(string | number)[]>([])
31
+ const pagination = ref<PaginationState>({ page: 1, pageSize: 5, total: data.length })
32
+ </script>
33
+
34
+ <template>
35
+ <Story title="Data Display/DataFrame">
36
+ <Variant title="Playground">
37
+ <template #default="{ state }">
38
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
39
+ <DataFrame
40
+ :data="data"
41
+ :columns="columns"
42
+ row-key="id"
43
+ :striped="state.striped"
44
+ :bordered="state.bordered"
45
+ :sortable="state.sortable"
46
+ :searchable="state.searchable"
47
+ :selectable="state.selectable"
48
+ :loading="state.loading"
49
+ :size="state.size"
50
+ :sticky-header="state.stickyHeader"
51
+ :selected-keys="selectedKeys"
52
+ @update:selected-keys="selectedKeys = $event"
53
+ />
54
+ </div>
55
+ </template>
56
+
57
+ <template #controls="{ state }">
58
+ <HstSelect
59
+ v-model="state.size"
60
+ title="Size"
61
+ :options="['sm', 'md', 'lg'].map(s => ({ label: s, value: s }))"
62
+ />
63
+ <HstCheckbox v-model="state.striped" title="Striped" />
64
+ <HstCheckbox v-model="state.bordered" title="Bordered" />
65
+ <HstCheckbox v-model="state.sortable" title="Sortable" />
66
+ <HstCheckbox v-model="state.searchable" title="Searchable" />
67
+ <HstCheckbox v-model="state.selectable" title="Selectable" />
68
+ <HstCheckbox v-model="state.stickyHeader" title="Sticky Header" />
69
+ <HstCheckbox v-model="state.loading" title="Loading" />
70
+ </template>
71
+ </Variant>
72
+
73
+ <Variant title="Sortable with Search">
74
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
75
+ <DataFrame
76
+ :data="data"
77
+ :columns="columns"
78
+ row-key="id"
79
+ sortable
80
+ searchable
81
+ search-placeholder="Search compounds, wells..."
82
+ />
83
+ </div>
84
+ </Variant>
85
+
86
+ <Variant title="With Pagination">
87
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
88
+ <DataFrame
89
+ :data="data"
90
+ :columns="columns"
91
+ row-key="id"
92
+ sortable
93
+ :pagination="pagination"
94
+ @update:pagination="pagination = $event"
95
+ />
96
+ </div>
97
+ </Variant>
98
+
99
+ <Variant title="Selectable Rows">
100
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
101
+ <DataFrame
102
+ :data="data"
103
+ :columns="columns"
104
+ row-key="id"
105
+ selectable
106
+ :selected-keys="selectedKeys"
107
+ @update:selected-keys="selectedKeys = $event"
108
+ />
109
+ <p style="margin-top: 1rem; font-size: 0.875rem; color: var(--text-muted, #94a3b8);">
110
+ Selected IDs: {{ selectedKeys.length ? selectedKeys.join(', ') : 'none' }}
111
+ </p>
112
+ </div>
113
+ </Variant>
114
+
115
+ <Variant title="Loading State">
116
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
117
+ <DataFrame
118
+ :data="[]"
119
+ :columns="columns"
120
+ loading
121
+ />
122
+ </div>
123
+ </Variant>
124
+
125
+ <Variant title="Empty State">
126
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
127
+ <DataFrame
128
+ :data="[]"
129
+ :columns="columns"
130
+ empty-text="No experiment results found. Run an analysis to populate this table."
131
+ />
132
+ </div>
133
+ </Variant>
134
+
135
+ <Variant title="Compact (sm)">
136
+ <div style="padding: 2rem; max-width: 900px; margin: 0 auto;">
137
+ <DataFrame
138
+ :data="data"
139
+ :columns="columns"
140
+ row-key="id"
141
+ size="sm"
142
+ sortable
143
+ bordered
144
+ />
145
+ </div>
146
+ </Variant>
147
+ </Story>
148
+ </template>