@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,363 @@
1
+ <script setup lang="ts">
2
+ /** Month calendar for single date, multi-date, or range selection with markers and navigation. */
3
+ import { ref, computed, watch } from 'vue'
4
+ import type { CalendarSelectionMode, CalendarMarker, CalendarDayContext } from '../types'
5
+
6
+ /**
7
+ * Calendar - Month calendar with date selection, range selection, and custom markers.
8
+ *
9
+ * @example
10
+ * ```vue
11
+ * <!-- Single date selection -->
12
+ * <Calendar v-model="selectedDate" />
13
+ *
14
+ * <!-- Range selection -->
15
+ * <Calendar v-model="dateRange" selection-mode="range" />
16
+ *
17
+ * <!-- With markers -->
18
+ * <Calendar :markers="[{ date: '2024-01-15', color: '#ff0000', label: 'Event' }]" />
19
+ * ```
20
+ */
21
+ interface Props {
22
+ /** Selected date(s) - type depends on selectionMode */
23
+ modelValue?: Date | Date[] | { start: Date; end: Date } | null
24
+ /** Selection behavior mode */
25
+ selectionMode?: CalendarSelectionMode
26
+ /** Display month (0-11) */
27
+ month?: number
28
+ /** Display year */
29
+ year?: number
30
+ /** Always show 6 weeks (42 days) */
31
+ fixedWeeks?: boolean
32
+ /** First day of week (0=Sunday, 1=Monday, etc.) */
33
+ weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6
34
+ /** Show days from adjacent months */
35
+ showOutsideDays?: boolean
36
+ /** Show month navigation buttons */
37
+ showNavigation?: boolean
38
+ /** Visual markers on specific dates */
39
+ markers?: CalendarMarker[]
40
+ /** Earliest selectable date */
41
+ minDate?: Date | string
42
+ /** Latest selectable date */
43
+ maxDate?: Date | string
44
+ /** Explicitly disabled dates */
45
+ disabledDates?: Array<Date | string>
46
+ /** Custom disabled date logic */
47
+ isDateDisabled?: (date: Date) => boolean
48
+ /** Locale for date formatting */
49
+ locale?: string
50
+ }
51
+
52
+ const props = withDefaults(defineProps<Props>(), {
53
+ selectionMode: 'single',
54
+ fixedWeeks: true,
55
+ weekStartsOn: 1,
56
+ showOutsideDays: true,
57
+ showNavigation: true,
58
+ markers: () => [],
59
+ disabledDates: () => [],
60
+ locale: 'en-US',
61
+ })
62
+
63
+ /**
64
+ * @event update:modelValue - Emitted when date selection changes (v-model support)
65
+ * @event update:month - Emitted when displayed month changes
66
+ * @event update:year - Emitted when displayed year changes
67
+ * @event day-click - Emitted when a day is clicked, includes day context
68
+ * @event navigate - Emitted when month navigation occurs
69
+ */
70
+ const emit = defineEmits<{
71
+ 'update:modelValue': [value: Date | Date[] | { start: Date; end: Date } | null]
72
+ 'update:month': [month: number]
73
+ 'update:year': [year: number]
74
+ 'day-click': [context: CalendarDayContext]
75
+ navigate: [direction: 'prev' | 'next', month: number, year: number]
76
+ }>()
77
+
78
+ const today = new Date()
79
+ today.setHours(0, 0, 0, 0)
80
+
81
+ const currentMonth = ref(props.month ?? today.getMonth())
82
+ const currentYear = ref(props.year ?? today.getFullYear())
83
+
84
+ // Range hover tracking
85
+ const hoveredDate = ref<Date | null>(null)
86
+
87
+ watch(() => props.month, (val) => { if (val !== undefined) currentMonth.value = val })
88
+ watch(() => props.year, (val) => { if (val !== undefined) currentYear.value = val })
89
+
90
+ const monthLabel = computed(() => {
91
+ const date = new Date(currentYear.value, currentMonth.value, 1)
92
+ return date.toLocaleDateString(props.locale, { month: 'long', year: 'numeric' })
93
+ })
94
+
95
+ const weekDayLabels = computed(() => {
96
+ const labels: string[] = []
97
+ // Use Jan 7, 2024 (Sunday) as reference, then offset by weekStartsOn
98
+ const base = new Date(2024, 0, 7 + props.weekStartsOn)
99
+ for (let i = 0; i < 7; i++) {
100
+ const d = new Date(base)
101
+ d.setDate(d.getDate() + i)
102
+ labels.push(d.toLocaleDateString(props.locale, { weekday: 'short' }))
103
+ }
104
+ return labels
105
+ })
106
+
107
+ function toDateKey(d: Date): string {
108
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
109
+ }
110
+
111
+ function parseDate(val: Date | string): Date {
112
+ if (val instanceof Date) return val
113
+ const d = new Date(val + 'T00:00:00')
114
+ return d
115
+ }
116
+
117
+ function isSameDay(a: Date, b: Date): boolean {
118
+ return a.getFullYear() === b.getFullYear() &&
119
+ a.getMonth() === b.getMonth() &&
120
+ a.getDate() === b.getDate()
121
+ }
122
+
123
+ const disabledDateSet = computed(() => {
124
+ const set = new Set<string>()
125
+ for (const d of props.disabledDates) {
126
+ const parsed = parseDate(d)
127
+ set.add(toDateKey(parsed))
128
+ }
129
+ return set
130
+ })
131
+
132
+ const markerMap = computed(() => {
133
+ const map = new Map<string, CalendarMarker[]>()
134
+ for (const marker of props.markers) {
135
+ const date = parseDate(marker.date)
136
+ const key = toDateKey(date)
137
+ if (!map.has(key)) map.set(key, [])
138
+ map.get(key)!.push(marker)
139
+ }
140
+ return map
141
+ })
142
+
143
+ function isDateSelected(date: Date): boolean {
144
+ const val = props.modelValue
145
+ if (!val) return false
146
+ if (val instanceof Date) return isSameDay(date, val)
147
+ if (Array.isArray(val)) return val.some(d => isSameDay(date, d))
148
+ if ('start' in val && 'end' in val) {
149
+ return isSameDay(date, val.start) || isSameDay(date, val.end)
150
+ }
151
+ return false
152
+ }
153
+
154
+ function isInRange(date: Date): boolean {
155
+ if (props.selectionMode !== 'range') return false
156
+ const val = props.modelValue
157
+ if (!val || !('start' in (val as object))) return false
158
+ const range = val as { start: Date; end: Date }
159
+
160
+ const t = date.getTime()
161
+ const start = range.start?.getTime()
162
+ if (!start) return false
163
+
164
+ // If hovering during selection (before end is set)
165
+ if (!range.end && hoveredDate.value) {
166
+ const hov = hoveredDate.value.getTime()
167
+ const [lo, hi] = start <= hov ? [start, hov] : [hov, start]
168
+ return t > lo && t < hi
169
+ }
170
+
171
+ // Complete range
172
+ if (range.end) {
173
+ const end = range.end.getTime()
174
+ return t > start && t < end
175
+ }
176
+
177
+ return false
178
+ }
179
+
180
+ function isDisabled(date: Date): boolean {
181
+ if (disabledDateSet.value.has(toDateKey(date))) return true
182
+ if (props.isDateDisabled?.(date)) return true
183
+ if (props.minDate) {
184
+ const min = parseDate(props.minDate)
185
+ if (date < min) return true
186
+ }
187
+ if (props.maxDate) {
188
+ const max = parseDate(props.maxDate)
189
+ if (date > max) return true
190
+ }
191
+ return false
192
+ }
193
+
194
+ const calendarDays = computed<CalendarDayContext[]>(() => {
195
+ const first = new Date(currentYear.value, currentMonth.value, 1)
196
+ const startDow = first.getDay()
197
+ const offset = (startDow - props.weekStartsOn + 7) % 7
198
+
199
+ const totalCells = props.fixedWeeks ? 42 : (() => {
200
+ const daysInMonth = new Date(currentYear.value, currentMonth.value + 1, 0).getDate()
201
+ const needed = offset + daysInMonth
202
+ return Math.ceil(needed / 7) * 7
203
+ })()
204
+
205
+ const days: CalendarDayContext[] = []
206
+ for (let i = 0; i < totalCells; i++) {
207
+ const date = new Date(currentYear.value, currentMonth.value, 1 - offset + i)
208
+ date.setHours(0, 0, 0, 0)
209
+ const key = toDateKey(date)
210
+ days.push({
211
+ date,
212
+ dayOfMonth: date.getDate(),
213
+ isToday: isSameDay(date, today),
214
+ isSelected: isDateSelected(date),
215
+ isInRange: isInRange(date),
216
+ isDisabled: isDisabled(date),
217
+ isOutsideMonth: date.getMonth() !== currentMonth.value,
218
+ markers: markerMap.value.get(key) ?? [],
219
+ })
220
+ }
221
+ return days
222
+ })
223
+
224
+ // Range selection state
225
+ const rangeStart = ref<Date | null>(null)
226
+
227
+ function handleDayClick(day: CalendarDayContext) {
228
+ if (day.isDisabled) return
229
+ if (!props.showOutsideDays && day.isOutsideMonth) return
230
+
231
+ emit('day-click', day)
232
+
233
+ if (props.selectionMode === 'none') return
234
+
235
+ if (props.selectionMode === 'single') {
236
+ emit('update:modelValue', day.date)
237
+ } else if (props.selectionMode === 'multiple') {
238
+ const current = (props.modelValue as Date[] | undefined) ?? []
239
+ const idx = current.findIndex(d => isSameDay(d, day.date))
240
+ if (idx >= 0) {
241
+ const next = [...current]
242
+ next.splice(idx, 1)
243
+ emit('update:modelValue', next)
244
+ } else {
245
+ emit('update:modelValue', [...current, day.date])
246
+ }
247
+ } else if (props.selectionMode === 'range') {
248
+ if (!rangeStart.value) {
249
+ rangeStart.value = day.date
250
+ } else {
251
+ const start = rangeStart.value
252
+ const end = day.date
253
+ rangeStart.value = null
254
+ const ordered = start.getTime() <= end.getTime()
255
+ ? { start, end }
256
+ : { start: end, end: start }
257
+ emit('update:modelValue', ordered)
258
+ }
259
+ }
260
+ }
261
+
262
+ function handleDayHover(day: CalendarDayContext) {
263
+ if (props.selectionMode === 'range' && rangeStart.value) {
264
+ hoveredDate.value = day.date
265
+ }
266
+ }
267
+
268
+ function prevMonth() {
269
+ if (currentMonth.value === 0) {
270
+ currentMonth.value = 11
271
+ currentYear.value--
272
+ emit('update:year', currentYear.value)
273
+ } else {
274
+ currentMonth.value--
275
+ }
276
+ emit('update:month', currentMonth.value)
277
+ emit('navigate', 'prev', currentMonth.value, currentYear.value)
278
+ }
279
+
280
+ function nextMonth() {
281
+ if (currentMonth.value === 11) {
282
+ currentMonth.value = 0
283
+ currentYear.value++
284
+ emit('update:year', currentYear.value)
285
+ } else {
286
+ currentMonth.value++
287
+ }
288
+ emit('update:month', currentMonth.value)
289
+ emit('navigate', 'next', currentMonth.value, currentYear.value)
290
+ }
291
+ </script>
292
+
293
+ <template>
294
+ <div class="mld-calendar">
295
+ <div v-if="showNavigation" class="mld-calendar__header">
296
+ <button type="button" class="mld-calendar__nav-btn" aria-label="Previous month" @click="prevMonth">
297
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
298
+ <path d="m15 18-6-6 6-6" />
299
+ </svg>
300
+ </button>
301
+ <slot name="header" :month="currentMonth" :year="currentYear" :prev-month="prevMonth" :next-month="nextMonth">
302
+ <span class="mld-calendar__title">{{ monthLabel }}</span>
303
+ </slot>
304
+ <button type="button" class="mld-calendar__nav-btn" aria-label="Next month" @click="nextMonth">
305
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
306
+ <path d="m9 18 6-6-6-6" />
307
+ </svg>
308
+ </button>
309
+ </div>
310
+
311
+ <div class="mld-calendar__weekdays">
312
+ <span
313
+ v-for="(label, i) in weekDayLabels"
314
+ :key="i"
315
+ class="mld-calendar__weekday"
316
+ >
317
+ <slot name="week-day" :day-name="label" :index="i">{{ label }}</slot>
318
+ </span>
319
+ </div>
320
+
321
+ <div class="mld-calendar__grid">
322
+ <button
323
+ v-for="(day, i) in calendarDays"
324
+ :key="i"
325
+ type="button"
326
+ :disabled="day.isDisabled"
327
+ :class="[
328
+ 'mld-calendar__day',
329
+ {
330
+ 'mld-calendar__day--today': day.isToday,
331
+ 'mld-calendar__day--selected': day.isSelected,
332
+ 'mld-calendar__day--in-range': day.isInRange,
333
+ 'mld-calendar__day--disabled': day.isDisabled,
334
+ 'mld-calendar__day--outside': day.isOutsideMonth,
335
+ 'mld-calendar__day--interactive': selectionMode !== 'none' && !day.isDisabled,
336
+ },
337
+ ]"
338
+ @click="handleDayClick(day)"
339
+ @mouseenter="handleDayHover(day)"
340
+ >
341
+ <slot name="day-content" :day="day">
342
+ <span class="mld-calendar__day-number">{{ day.dayOfMonth }}</span>
343
+ <div v-if="day.markers.length > 0" class="mld-calendar__markers">
344
+ <span
345
+ v-for="(marker, mi) in day.markers.slice(0, 3)"
346
+ :key="mi"
347
+ :class="[
348
+ 'mld-calendar__marker',
349
+ `mld-calendar__marker--${marker.type ?? 'dot'}`,
350
+ ]"
351
+ :style="marker.color ? { '--marker-color': marker.color } : {}"
352
+ :title="marker.label"
353
+ />
354
+ </div>
355
+ </slot>
356
+ </button>
357
+ </div>
358
+ </div>
359
+ </template>
360
+
361
+ <style>
362
+ @import '../styles/components/calendar.css';
363
+ </style>
@@ -0,0 +1,113 @@
1
+ <script setup lang="ts">
2
+ import ChartContainer from './ChartContainer.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <Story title="Data Display/ChartContainer">
7
+ <Variant title="Playground">
8
+ <template #default="{ state }">
9
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
10
+ <ChartContainer
11
+ :title="state.showTitle ? state.title : undefined"
12
+ :description="state.showDescription ? state.description : undefined"
13
+ :loading="state.loading"
14
+ :empty="state.empty"
15
+ :empty-message="state.emptyMessage"
16
+ >
17
+ <div style="height: 300px; display: flex; align-items: center; justify-content: center; color: var(--text-muted, #94a3b8); font-style: italic; border: 2px dashed var(--border-color, #e2e8f0); border-radius: 0.5rem;">
18
+ Chart content goes here (e.g. Chart.js, D3, etc.)
19
+ </div>
20
+ </ChartContainer>
21
+ </div>
22
+ </template>
23
+
24
+ <template #controls="{ state }">
25
+ <HstCheckbox v-model="state.showTitle" title="Show Title" />
26
+ <HstText v-model="state.title" title="Title" />
27
+ <HstCheckbox v-model="state.showDescription" title="Show Description" />
28
+ <HstText v-model="state.description" title="Description" />
29
+ <HstCheckbox v-model="state.loading" title="Loading" />
30
+ <HstCheckbox v-model="state.empty" title="Empty" />
31
+ <HstText v-model="state.emptyMessage" title="Empty Message" />
32
+ </template>
33
+ </Variant>
34
+
35
+ <Variant title="With Title and Description">
36
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
37
+ <ChartContainer
38
+ title="Dose-Response Curve"
39
+ description="IC50 analysis for compound MINT-2847 across 8-point dilution series"
40
+ >
41
+ <div style="height: 300px; display: flex; align-items: center; justify-content: center; color: var(--text-muted, #94a3b8); font-style: italic; border: 2px dashed var(--border-color, #e2e8f0); border-radius: 0.5rem;">
42
+ Sigmoidal dose-response chart placeholder
43
+ </div>
44
+ </ChartContainer>
45
+ </div>
46
+ </Variant>
47
+
48
+ <Variant title="Loading State">
49
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
50
+ <ChartContainer
51
+ title="Cell Viability Heatmap"
52
+ description="Processing 96-well plate data..."
53
+ loading
54
+ >
55
+ <div style="height: 300px;" />
56
+ </ChartContainer>
57
+ </div>
58
+ </Variant>
59
+
60
+ <Variant title="Empty State">
61
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
62
+ <ChartContainer
63
+ title="Experiment Results"
64
+ empty
65
+ empty-message="No results found. Run an analysis to see data here."
66
+ />
67
+ </div>
68
+ </Variant>
69
+
70
+ <Variant title="With Toolbar Slot">
71
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
72
+ <ChartContainer title="Proliferation Assay">
73
+ <template #toolbar>
74
+ <div style="display: flex; gap: 0.5rem;">
75
+ <button type="button" style="padding: 0.25rem 0.75rem; font-size: 0.8125rem; border: 1px solid var(--border-color, #e2e8f0); border-radius: 0.375rem; background: var(--bg-card, #fff); color: var(--text-primary, #1e293b); cursor: pointer;">
76
+ Linear
77
+ </button>
78
+ <button type="button" style="padding: 0.25rem 0.75rem; font-size: 0.8125rem; border: 1px solid var(--mint-primary, #3B82F6); border-radius: 0.375rem; background: var(--mint-primary, #3B82F6); color: #fff; cursor: pointer;">
79
+ Log
80
+ </button>
81
+ </div>
82
+ </template>
83
+ <div style="height: 300px; display: flex; align-items: center; justify-content: center; color: var(--text-muted, #94a3b8); font-style: italic; border: 2px dashed var(--border-color, #e2e8f0); border-radius: 0.5rem;">
84
+ Chart with toolbar controls
85
+ </div>
86
+ </ChartContainer>
87
+ </div>
88
+ </Variant>
89
+
90
+ <Variant title="With Legend Slot">
91
+ <div style="padding: 2rem; max-width: 700px; margin: 0 auto;">
92
+ <ChartContainer title="Multi-Compound Comparison">
93
+ <div style="height: 250px; display: flex; align-items: center; justify-content: center; color: var(--text-muted, #94a3b8); font-style: italic; border: 2px dashed var(--border-color, #e2e8f0); border-radius: 0.5rem;">
94
+ Overlay chart placeholder
95
+ </div>
96
+ <template #legend>
97
+ <div style="display: flex; gap: 1.5rem; justify-content: center; font-size: 0.8125rem; color: var(--text-primary, #1e293b);">
98
+ <span style="display: flex; align-items: center; gap: 0.375rem;">
99
+ <span style="width: 12px; height: 12px; border-radius: 50%; background: #3B82F6;" /> MINT-2847
100
+ </span>
101
+ <span style="display: flex; align-items: center; gap: 0.375rem;">
102
+ <span style="width: 12px; height: 12px; border-radius: 50%; background: #EC4899;" /> MINT-3192
103
+ </span>
104
+ <span style="display: flex; align-items: center; gap: 0.375rem;">
105
+ <span style="width: 12px; height: 12px; border-radius: 50%; background: #10B981;" /> Vehicle
106
+ </span>
107
+ </div>
108
+ </template>
109
+ </ChartContainer>
110
+ </div>
111
+ </Variant>
112
+ </Story>
113
+ </template>
@@ -0,0 +1,64 @@
1
+ <script setup lang="ts">
2
+ /** Wraps a chart with header, toolbar slot, loading overlay, empty state, and legend slot. */
3
+ import LoadingSpinner from './LoadingSpinner.vue'
4
+ import EmptyState from './EmptyState.vue'
5
+
6
+ interface Props {
7
+ title?: string
8
+ description?: string
9
+ loading?: boolean
10
+ empty?: boolean
11
+ emptyMessage?: string
12
+ }
13
+
14
+ withDefaults(defineProps<Props>(), {
15
+ loading: false,
16
+ empty: false,
17
+ emptyMessage: 'No data available',
18
+ })
19
+ </script>
20
+
21
+ <template>
22
+ <div class="mld-chart">
23
+ <div v-if="title || description || $slots.toolbar" class="mld-chart__header">
24
+ <div v-if="title || description" class="mld-chart__header-text">
25
+ <h3 v-if="title" class="mld-chart__title">{{ title }}</h3>
26
+ <p v-if="description" class="mld-chart__description">{{ description }}</p>
27
+ </div>
28
+ <div v-if="$slots.toolbar" class="mld-chart__toolbar">
29
+ <slot name="toolbar" />
30
+ </div>
31
+ </div>
32
+
33
+ <div class="mld-chart__body">
34
+ <!-- Loading overlay -->
35
+ <div v-if="loading" class="mld-chart__loading-overlay">
36
+ <LoadingSpinner size="lg" />
37
+ </div>
38
+
39
+ <!-- Empty state -->
40
+ <template v-else-if="empty">
41
+ <slot name="empty">
42
+ <EmptyState
43
+ :title="emptyMessage"
44
+ size="sm"
45
+ icon-path="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z"
46
+ />
47
+ </slot>
48
+ </template>
49
+
50
+ <!-- Chart content -->
51
+ <template v-else>
52
+ <slot />
53
+ </template>
54
+ </div>
55
+
56
+ <div v-if="$slots.legend" class="mld-chart__legend">
57
+ <slot name="legend" />
58
+ </div>
59
+ </div>
60
+ </template>
61
+
62
+ <style>
63
+ @import '../styles/components/chart-container.css';
64
+ </style>
@@ -0,0 +1,102 @@
1
+ <script setup lang="ts">
2
+ import ChemicalFormula from './ChemicalFormula.vue'
3
+
4
+ const formulas = [
5
+ { formula: 'H2O', name: 'Water' },
6
+ { formula: 'NaCl', name: 'Sodium Chloride' },
7
+ { formula: 'C6H12O6', name: 'Glucose' },
8
+ { formula: 'Ca(OH)2', name: 'Calcium Hydroxide' },
9
+ { formula: 'H2SO4', name: 'Sulfuric Acid' },
10
+ { formula: 'CH3COOH', name: 'Acetic Acid' },
11
+ { formula: 'C2H5OH', name: 'Ethanol' },
12
+ { formula: 'NH3', name: 'Ammonia' },
13
+ { formula: 'CuSO4.5H2O', name: 'Copper Sulfate Pentahydrate' },
14
+ { formula: 'Fe2O3', name: 'Iron(III) Oxide' },
15
+ ]
16
+ </script>
17
+
18
+ <template>
19
+ <Story title="Data Display/ChemicalFormula">
20
+ <Variant title="Playground">
21
+ <template #default="{ state }">
22
+ <div style="padding: 2rem; display: flex; align-items: center; justify-content: center; font-size: 1.5rem;">
23
+ <ChemicalFormula :formula="state.formula" :inline="state.inline" />
24
+ </div>
25
+ </template>
26
+
27
+ <template #controls="{ state }">
28
+ <HstText v-model="state.formula" title="Formula" />
29
+ <HstCheckbox v-model="state.inline" title="Inline" />
30
+ </template>
31
+ </Variant>
32
+
33
+ <Variant title="Common Formulas">
34
+ <div style="padding: 2rem; max-width: 500px; margin: 0 auto;">
35
+ <table style="width: 100%; border-collapse: collapse; font-size: 1rem;">
36
+ <thead>
37
+ <tr>
38
+ <th style="text-align: left; padding: 0.75rem 0.5rem; border-bottom: 2px solid var(--border-color, #e2e8f0); color: var(--text-muted, #94a3b8); font-weight: 600;">Name</th>
39
+ <th style="text-align: left; padding: 0.75rem 0.5rem; border-bottom: 2px solid var(--border-color, #e2e8f0); color: var(--text-muted, #94a3b8); font-weight: 600;">Formula</th>
40
+ <th style="text-align: left; padding: 0.75rem 0.5rem; border-bottom: 2px solid var(--border-color, #e2e8f0); color: var(--text-muted, #94a3b8); font-weight: 600;">Rendered</th>
41
+ </tr>
42
+ </thead>
43
+ <tbody>
44
+ <tr v-for="item in formulas" :key="item.formula">
45
+ <td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color, #e2e8f0); color: var(--text-primary, #1e293b);">{{ item.name }}</td>
46
+ <td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color, #e2e8f0); font-family: monospace; color: var(--text-muted, #94a3b8);">{{ item.formula }}</td>
47
+ <td style="padding: 0.5rem; border-bottom: 1px solid var(--border-color, #e2e8f0); color: var(--text-primary, #1e293b); font-size: 1.125rem;">
48
+ <ChemicalFormula :formula="item.formula" />
49
+ </td>
50
+ </tr>
51
+ </tbody>
52
+ </table>
53
+ </div>
54
+ </Variant>
55
+
56
+ <Variant title="Inline in Text">
57
+ <div style="padding: 2rem; max-width: 600px; margin: 0 auto; line-height: 1.8; color: var(--text-primary, #1e293b);">
58
+ <p style="margin: 0 0 1rem;">
59
+ The reaction of <ChemicalFormula formula="NaOH" /> with <ChemicalFormula formula="HCl" /> produces
60
+ <ChemicalFormula formula="NaCl" /> and <ChemicalFormula formula="H2O" />.
61
+ </p>
62
+ <p style="margin: 0 0 1rem;">
63
+ Photosynthesis converts <ChemicalFormula formula="CO2" /> and <ChemicalFormula formula="H2O" />
64
+ into <ChemicalFormula formula="C6H12O6" /> and <ChemicalFormula formula="O2" />.
65
+ </p>
66
+ <p style="margin: 0;">
67
+ The drug compound was dissolved in <ChemicalFormula formula="(CH3)2SO" /> (DMSO) at a stock
68
+ concentration of 10 mM.
69
+ </p>
70
+ </div>
71
+ </Variant>
72
+
73
+ <Variant title="Block Display">
74
+ <div style="padding: 2rem; display: flex; flex-direction: column; gap: 1rem; align-items: center; font-size: 1.5rem;">
75
+ <ChemicalFormula formula="C6H12O6" :inline="false" />
76
+ <ChemicalFormula formula="Ca(OH)2" :inline="false" />
77
+ <ChemicalFormula formula="CuSO4.5H2O" :inline="false" />
78
+ </div>
79
+ </Variant>
80
+
81
+ <Variant title="Complex Formulas">
82
+ <div style="padding: 2rem; display: flex; flex-direction: column; gap: 1.25rem; align-items: center; font-size: 1.25rem;">
83
+ <div style="display: flex; gap: 0.75rem; align-items: baseline;">
84
+ <span style="min-width: 180px; text-align: right; color: var(--text-muted, #94a3b8); font-size: 0.875rem;">Aspirin:</span>
85
+ <ChemicalFormula formula="C9H8O4" />
86
+ </div>
87
+ <div style="display: flex; gap: 0.75rem; align-items: baseline;">
88
+ <span style="min-width: 180px; text-align: right; color: var(--text-muted, #94a3b8); font-size: 0.875rem;">Caffeine:</span>
89
+ <ChemicalFormula formula="C8H10N4O2" />
90
+ </div>
91
+ <div style="display: flex; gap: 0.75rem; align-items: baseline;">
92
+ <span style="min-width: 180px; text-align: right; color: var(--text-muted, #94a3b8); font-size: 0.875rem;">ATP:</span>
93
+ <ChemicalFormula formula="C10H16N5O13P3" />
94
+ </div>
95
+ <div style="display: flex; gap: 0.75rem; align-items: baseline;">
96
+ <span style="min-width: 180px; text-align: right; color: var(--text-muted, #94a3b8); font-size: 0.875rem;">Hemoglobin subunit:</span>
97
+ <ChemicalFormula formula="C738H1166N812O203S2Fe" />
98
+ </div>
99
+ </div>
100
+ </Variant>
101
+ </Story>
102
+ </template>
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ /** Renders a chemical formula string (H₂O, C₆H₁₂O₆, Ca(OH)₂) with typographically correct subscripts and superscripts for charges. */
3
+ import { useChemicalFormula, type FormulaPart } from '../composables/useChemicalFormula'
4
+
5
+ interface Props {
6
+ formula: string
7
+ inline?: boolean
8
+ }
9
+
10
+ withDefaults(defineProps<Props>(), {
11
+ inline: true,
12
+ })
13
+
14
+ const { renderFormulaParts } = useChemicalFormula()
15
+
16
+ function getParts(f: string): FormulaPart[] {
17
+ return renderFormulaParts(f)
18
+ }
19
+ </script>
20
+
21
+ <template>
22
+ <component
23
+ :is="inline ? 'span' : 'div'"
24
+ :class="['mld-chem-formula', !inline ? 'mld-chem-formula--block' : '']"
25
+ >
26
+ <template v-for="(part, i) in getParts(formula)" :key="i">
27
+ <span v-if="part.type === 'element'" class="mld-chem-formula__element">{{ part.text }}</span>
28
+ <span v-else-if="part.type === 'subscript'" class="mld-chem-formula__subscript">{{ part.text }}</span>
29
+ <span v-else-if="part.type === 'superscript'" class="mld-chem-formula__superscript">{{ part.text }}</span>
30
+ <span v-else-if="part.type === 'paren'" class="mld-chem-formula__paren">{{ part.text }}</span>
31
+ <span v-else-if="part.type === 'dot'" class="mld-chem-formula__dot">{{ part.text }}</span>
32
+ <span v-else-if="part.type === 'charge'" class="mld-chem-formula__charge">{{ part.text }}</span>
33
+ </template>
34
+ </component>
35
+ </template>
36
+
37
+ <style>
38
+ @import '../styles/components/chemical-formula.css';
39
+ </style>