@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,197 @@
1
+ import type { FieldRules } from '../composables/useForm'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Field types
5
+ // ---------------------------------------------------------------------------
6
+
7
+ /** All supported field types that map to SDK components. */
8
+ export type FormFieldType =
9
+ | 'text'
10
+ | 'email'
11
+ | 'password'
12
+ | 'number'
13
+ | 'tel'
14
+ | 'url'
15
+ | 'search'
16
+ | 'textarea'
17
+ | 'select'
18
+ | 'multiselect'
19
+ | 'checkbox'
20
+ | 'toggle'
21
+ | 'radio'
22
+ | 'slider'
23
+ | 'tags'
24
+ | 'date'
25
+ | 'time'
26
+ | 'datetime'
27
+ | 'file'
28
+ | 'formula'
29
+ | 'sequence'
30
+ | 'molecule'
31
+ | 'concentration'
32
+ | 'unit'
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Conditions (JSON-serializable)
36
+ // ---------------------------------------------------------------------------
37
+
38
+ export type FieldCondition =
39
+ | { field: string; eq: unknown }
40
+ | { field: string; neq: unknown }
41
+ | { field: string; gt: number }
42
+ | { field: string; lt: number }
43
+ | { field: string; gte: number }
44
+ | { field: string; lte: number }
45
+ | { field: string; in: unknown[] }
46
+ | { field: string; notIn: unknown[] }
47
+ | { field: string; truthy: true }
48
+ | { field: string; falsy: true }
49
+ | { field: string; contains: string }
50
+ | { and: FieldCondition[] }
51
+ | { or: FieldCondition[] }
52
+ | { not: FieldCondition }
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Validation (JSON-safe subset of FieldRules)
56
+ // ---------------------------------------------------------------------------
57
+
58
+ export interface FieldValidation {
59
+ required?: boolean | string
60
+ minLength?: number | { value: number; message: string }
61
+ maxLength?: number | { value: number; message: string }
62
+ min?: number | { value: number; message: string }
63
+ max?: number | { value: number; message: string }
64
+ /** Pattern as a string (converted to RegExp at runtime). */
65
+ pattern?: string | { value: string; message: string }
66
+ email?: boolean | string
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // Field schema
71
+ // ---------------------------------------------------------------------------
72
+
73
+ export interface FormFieldSchema {
74
+ name: string
75
+ label: string
76
+ type: FormFieldType
77
+ defaultValue?: unknown
78
+ placeholder?: string
79
+ hint?: string
80
+ size?: 'sm' | 'md' | 'lg'
81
+ disabled?: boolean
82
+ readonly?: boolean
83
+ validation?: FieldValidation
84
+ condition?: FieldCondition
85
+ /** Grid column span (1-3). Defaults to 1. */
86
+ colSpan?: number
87
+ /** Extra props passed directly to the underlying component. */
88
+ props?: Record<string, unknown>
89
+ }
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // Section schema
93
+ // ---------------------------------------------------------------------------
94
+
95
+ export interface FormSectionSchema {
96
+ id: string
97
+ title: string
98
+ description?: string
99
+ collapsible?: boolean
100
+ defaultOpen?: boolean
101
+ /** Number of grid columns (1-3). Defaults to 1. */
102
+ columns?: 1 | 2 | 3
103
+ fields: FormFieldSchema[]
104
+ condition?: FieldCondition
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Wizard step schema
109
+ // ---------------------------------------------------------------------------
110
+
111
+ export interface FormStepSchema {
112
+ id: string
113
+ label: string
114
+ description?: string
115
+ icon?: string
116
+ optional?: boolean
117
+ sections: FormSectionSchema[]
118
+ }
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // Top-level form schema
122
+ // ---------------------------------------------------------------------------
123
+
124
+ export type FormSchema =
125
+ | {
126
+ sections: FormSectionSchema[]
127
+ steps?: never
128
+ submitLabel?: string
129
+ cancelLabel?: string
130
+ showCancel?: boolean
131
+ }
132
+ | {
133
+ sections?: never
134
+ steps: FormStepSchema[]
135
+ submitLabel?: string
136
+ cancelLabel?: string
137
+ showCancel?: boolean
138
+ }
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // Enhancements (TS-only, NOT JSON-serializable)
142
+ // ---------------------------------------------------------------------------
143
+
144
+ export interface FieldEnhancement<T extends Record<string, unknown> = Record<string, unknown>> {
145
+ /** Custom validator appended to the field's rules. */
146
+ validate?: (value: unknown, data: T) => string | undefined | null
147
+ /** Dynamic visibility (overrides schema condition if both present). */
148
+ visible?: (data: T) => boolean
149
+ /** Dynamic options for select/multiselect/radio fields. */
150
+ options?: (data: T) => { label: string; value: unknown }[]
151
+ /** Dynamic extra props merged into the component. */
152
+ props?: (data: T) => Record<string, unknown>
153
+ }
154
+
155
+ export interface FormEnhancements<T extends Record<string, unknown> = Record<string, unknown>> {
156
+ /** Per-field enhancements keyed by field name. */
157
+ fields?: Partial<Record<keyof T, FieldEnhancement<T>>>
158
+ /** Called on successful submit. */
159
+ onSubmit?: (data: T) => Promise<void> | void
160
+ /** Transform data before submit (return transformed copy). */
161
+ transform?: (data: T) => T | Record<string, unknown>
162
+ /** Called when any field value changes. */
163
+ onFieldChange?: (field: keyof T, value: unknown, data: T) => void
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // useFormBuilder return type
168
+ // ---------------------------------------------------------------------------
169
+
170
+ export interface UseFormBuilderReturn<T extends Record<string, unknown>> {
171
+ /** Underlying useForm return. */
172
+ form: import('../composables/useForm').UseFormReturn<T>
173
+ /** Validation rules derived from schema + enhancements. */
174
+ rules: Partial<Record<keyof T, FieldRules>>
175
+ /** Whether a field is currently visible. */
176
+ isFieldVisible: (name: string) => boolean
177
+ /** Whether a section is currently visible. */
178
+ isSectionVisible: (id: string) => boolean
179
+ /** All flattened field schemas. */
180
+ fields: FormFieldSchema[]
181
+ /** Resolve final component props for a field. */
182
+ getResolvedFieldProps: (field: FormFieldSchema) => Record<string, unknown>
183
+ /** Get options for a select/radio/multiselect field. */
184
+ getFieldOptions: (name: string) => { label: string; value: unknown }[] | undefined
185
+
186
+ // Wizard-specific
187
+ currentStep: import('vue').Ref<number>
188
+ isCurrentStepValid: import('vue').ComputedRef<boolean>
189
+ goNext: () => boolean
190
+ goBack: () => void
191
+ goToStep: (index: number) => void
192
+
193
+ // Actions
194
+ validate: () => boolean
195
+ reset: (values?: Partial<T>) => void
196
+ submit: () => Promise<void>
197
+ }
@@ -0,0 +1,207 @@
1
+ // Component types
2
+ export type {
3
+ ContainerDirection,
4
+ ButtonVariant,
5
+ ButtonSize,
6
+ InputType,
7
+ ModalSize,
8
+ ModalVariant,
9
+ AlertType,
10
+ Toast,
11
+ TabItem,
12
+ SelectOption,
13
+ RadioOption,
14
+ FormFieldProps,
15
+ SidebarToolSection,
16
+ CollapsibleState,
17
+ TopBarVariant,
18
+ TopBarPage,
19
+ TopBarTab,
20
+ TopBarTabOption,
21
+ TopBarSettingsConfig,
22
+ PillNavItem,
23
+ PageSelectorItem,
24
+ PluginSwitcherPlugin,
25
+ PluginSwitcherInfo,
26
+ AccountMenuItem,
27
+ // Well Plate types
28
+ WellPlateFormat,
29
+ WellState,
30
+ WellPlateSelectionMode,
31
+ WellPlateSize,
32
+ WellShape,
33
+ Well,
34
+ HeatmapColorScale,
35
+ HeatmapConfig,
36
+ // Well Plate editing types
37
+ SlotPosition,
38
+ WellExtendedData,
39
+ WellEditData,
40
+ WellEditField,
41
+ WellLegendItem,
42
+ PlateCondition,
43
+ ColumnCondition,
44
+ RowCondition,
45
+ Rack,
46
+ // Sample Legend types
47
+ SampleType,
48
+ // Plate Map Editor types
49
+ PlateMap,
50
+ PlateMapEditorState,
51
+ // Experiment Timeline types
52
+ ProtocolStepType,
53
+ ProtocolStepStatus,
54
+ ProtocolStep,
55
+ // Sample management types
56
+ SampleGroup,
57
+ GroupItem,
58
+ FileUploaderMode,
59
+ // SegmentedControl types
60
+ SegmentedOption,
61
+ SegmentedControlVariant,
62
+ SegmentedControlSize,
63
+ // MultiSelect types
64
+ MultiSelectOption,
65
+ MultiSelectSize,
66
+ // Pill types
67
+ PillVariant,
68
+ PillColor,
69
+ PillSize,
70
+ // Calendar types
71
+ CalendarSelectionMode,
72
+ CalendarMarker,
73
+ CalendarDayContext,
74
+ // DataFrame types
75
+ SortDirection,
76
+ SortState,
77
+ DataFrameColumn,
78
+ PaginationState,
79
+ // LoadingSpinner types
80
+ SpinnerSize,
81
+ SpinnerVariant,
82
+ // Divider types
83
+ DividerSpacing,
84
+ // StatusIndicator types
85
+ StatusType,
86
+ // ProgressBar types
87
+ ProgressVariant,
88
+ ProgressSize,
89
+ // Avatar types
90
+ AvatarSize,
91
+ // EmptyState types
92
+ EmptyStateColor,
93
+ EmptyStateSize,
94
+ // Breadcrumb types
95
+ BreadcrumbItem,
96
+ // Tooltip types
97
+ TooltipPosition,
98
+ // ConfirmDialog types
99
+ ConfirmVariant,
100
+ // SettingsModal types
101
+ SettingsTab,
102
+ // ScientificNumber types
103
+ NumberNotation,
104
+ // UnitInput types
105
+ UnitOption,
106
+ // StepWizard types
107
+ WizardStep,
108
+ WizardStepState,
109
+ // AuditTrail types
110
+ AuditEntryType,
111
+ AuditEntry,
112
+ // BatchProgressList types
113
+ BatchItemStatus,
114
+ BatchItem,
115
+ BatchSummary,
116
+ // TimePicker types
117
+ TimePickerFormat,
118
+ TimeRange,
119
+ // Schedule types
120
+ ScheduleView,
121
+ ScheduleEventStatus,
122
+ ScheduleEvent,
123
+ ScheduleBlockedSlot,
124
+ ScheduleSlotContext,
125
+ ScheduleEventCreateContext,
126
+ ScheduleEventUpdateContext,
127
+ // Summary data types
128
+ SummarySectionItem,
129
+ SummarySection,
130
+ SummaryData,
131
+ // Resource types
132
+ ResourceStatus,
133
+ ResourceSpec,
134
+ // MoleculeInput types
135
+ MoleculeData,
136
+ // Experiment selector types
137
+ ExperimentStatus,
138
+ DatePreset,
139
+ ExperimentSortField,
140
+ ExperimentTypeOption,
141
+ ExperimentSummary,
142
+ ExperimentListResponse,
143
+ ExperimentFilters,
144
+ // FitPanel types
145
+ FitState,
146
+ FitResultSummary,
147
+ // ReagentList types
148
+ StorageCondition,
149
+ ReagentColumn,
150
+ Reagent,
151
+ // SampleHierarchyTree types
152
+ TreeNodeType,
153
+ BadgeVariant,
154
+ TreeNode,
155
+ } from './components'
156
+
157
+ // FormBuilder types
158
+ export type {
159
+ FormFieldType,
160
+ FieldCondition,
161
+ FieldValidation,
162
+ FormFieldSchema,
163
+ FormSectionSchema,
164
+ FormStepSchema,
165
+ FormSchema,
166
+ FieldEnhancement,
167
+ FormEnhancements,
168
+ UseFormBuilderReturn,
169
+ } from './form-builder'
170
+
171
+ // Auto-group types
172
+ export type {
173
+ OutlierAction,
174
+ InputMode,
175
+ OutlierInfo,
176
+ ColumnInfo,
177
+ MetadataRow,
178
+ AutoGroupResult,
179
+ ParsedCsvData,
180
+ } from './auto-group'
181
+
182
+ // Auth types
183
+ export type {
184
+ AuthConfig,
185
+ UserInfo,
186
+ LoginResponse,
187
+ TokenVerifyResponse,
188
+ RegisterRequest,
189
+ UpdateProfileRequest,
190
+ CredentialInfo,
191
+ } from './auth'
192
+
193
+ // Platform types
194
+ export type {
195
+ PluginInfo,
196
+ PluginNavItem,
197
+ PluginSettings,
198
+ PluginSettingField,
199
+ PlatformContext,
200
+ PlatformContextOptions,
201
+ PlatformEventType,
202
+ PlatformEvent,
203
+ ThemeMode,
204
+ ColorPalette,
205
+ TableDensity,
206
+ UserSummary,
207
+ } from './platform'
@@ -0,0 +1,116 @@
1
+ // Plugin information provided by the platform
2
+ export interface PluginInfo {
3
+ id: string
4
+ name: string
5
+ version: string
6
+ description?: string
7
+ icon?: string
8
+ route_prefix: string
9
+ api_prefix: string
10
+ nav_items?: PluginNavItem[]
11
+ settings?: PluginSettings
12
+ }
13
+
14
+ // Plugin navigation item
15
+ export interface PluginNavItem {
16
+ id: string
17
+ label: string
18
+ path: string
19
+ icon?: string
20
+ children?: PluginNavItem[]
21
+ }
22
+
23
+ // Plugin settings schema
24
+ export interface PluginSettings {
25
+ [key: string]: PluginSettingField
26
+ }
27
+
28
+ export interface PluginSettingField {
29
+ type: 'string' | 'number' | 'boolean' | 'select' | 'multiselect'
30
+ label: string
31
+ description?: string
32
+ default?: unknown
33
+ options?: Array<{ value: string; label: string }>
34
+ validation?: {
35
+ required?: boolean
36
+ min?: number
37
+ max?: number
38
+ pattern?: string
39
+ }
40
+ }
41
+
42
+ // Minimal user representation used across experiment payloads and
43
+ // the injected platform context. shortname is a short attribution
44
+ // code (initials) used e.g. in generated filenames.
45
+ export interface UserSummary {
46
+ id: number
47
+ username: string
48
+ shortname?: string
49
+ first_name?: string
50
+ last_name?: string
51
+ }
52
+
53
+ // Platform context - available to plugins when running under MLD Platform
54
+ export interface PlatformContext {
55
+ // Is running under the MLD Platform
56
+ isIntegrated: boolean
57
+
58
+ // Plugin info (only available when integrated)
59
+ plugin?: PluginInfo
60
+
61
+ // Platform API base URL
62
+ platformApiUrl?: string
63
+
64
+ // Platform origin for message validation
65
+ // Used to verify postMessage sources and targets
66
+ platformOrigin?: string
67
+
68
+ // Current user info (if authenticated)
69
+ user?: {
70
+ id: string
71
+ username: string
72
+ role: string
73
+ shortname?: string
74
+ }
75
+
76
+ // Theme preference
77
+ theme: 'light' | 'dark' | 'system'
78
+
79
+ // Allowed experiment types for this plugin (from admin config)
80
+ allowedExperimentTypes?: string[] | null
81
+
82
+ // Features enabled in platform
83
+ features?: {
84
+ experiments?: boolean
85
+ passkey?: boolean
86
+ multiUser?: boolean
87
+ }
88
+ }
89
+
90
+ // Configuration options for usePlatformContext
91
+ export interface PlatformContextOptions {
92
+ // Allowed origins for postMessage communication
93
+ // If not specified, derives from platformApiUrl or uses same-origin only
94
+ allowedOrigins?: string[]
95
+
96
+ // Whether to allow messages from any origin (UNSAFE - only for development)
97
+ // Default: false
98
+ allowAnyOrigin?: boolean
99
+ }
100
+
101
+ // Platform event types for communication between plugin and platform
102
+ export type PlatformEventType =
103
+ | 'mld:theme-changed'
104
+ | 'mld:user-changed'
105
+ | 'mld:navigate'
106
+ | 'mld:notification'
107
+
108
+ export interface PlatformEvent<T = unknown> {
109
+ type: PlatformEventType
110
+ payload: T
111
+ }
112
+
113
+ // Settings state types
114
+ export type ThemeMode = 'light' | 'dark' | 'system'
115
+ export type ColorPalette = 'default' | 'colorblind' | 'viridis' | 'pastel'
116
+ export type TableDensity = 'compact' | 'normal' | 'comfortable'
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Color utilities for deriving same-hue-family shades.
3
+ *
4
+ * Used by SampleSelector and other group/legend UIs where a parent color
5
+ * needs to seed a gradient of related shades for its children.
6
+ */
7
+
8
+ export interface Hsl {
9
+ h: number // 0–360
10
+ s: number // 0–100
11
+ l: number // 0–100
12
+ }
13
+
14
+ const HEX_RE = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i
15
+
16
+ function clamp(n: number, min: number, max: number): number {
17
+ return Math.min(max, Math.max(min, n))
18
+ }
19
+
20
+ export function hexToHsl(hex: string): Hsl {
21
+ const match = HEX_RE.exec(hex.trim())
22
+ if (!match) return { h: 0, s: 0, l: 50 }
23
+
24
+ let raw = match[1]
25
+ if (raw.length === 3) raw = raw.split('').map(c => c + c).join('')
26
+
27
+ const r = parseInt(raw.slice(0, 2), 16) / 255
28
+ const g = parseInt(raw.slice(2, 4), 16) / 255
29
+ const b = parseInt(raw.slice(4, 6), 16) / 255
30
+
31
+ const max = Math.max(r, g, b)
32
+ const min = Math.min(r, g, b)
33
+ const delta = max - min
34
+
35
+ let h = 0
36
+ if (delta !== 0) {
37
+ if (max === r) h = ((g - b) / delta) % 6
38
+ else if (max === g) h = (b - r) / delta + 2
39
+ else h = (r - g) / delta + 4
40
+ }
41
+ h = (h * 60 + 360) % 360
42
+
43
+ const l = (max + min) / 2
44
+ const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1))
45
+
46
+ return { h, s: s * 100, l: l * 100 }
47
+ }
48
+
49
+ export function hslToHex(h: number, s: number, l: number): string {
50
+ const sNorm = clamp(s, 0, 100) / 100
51
+ const lNorm = clamp(l, 0, 100) / 100
52
+ const hNorm = ((h % 360) + 360) % 360
53
+
54
+ const c = (1 - Math.abs(2 * lNorm - 1)) * sNorm
55
+ const x = c * (1 - Math.abs(((hNorm / 60) % 2) - 1))
56
+ const m = lNorm - c / 2
57
+
58
+ let r = 0, g = 0, b = 0
59
+ if (hNorm < 60) [r, g, b] = [c, x, 0]
60
+ else if (hNorm < 120) [r, g, b] = [x, c, 0]
61
+ else if (hNorm < 180) [r, g, b] = [0, c, x]
62
+ else if (hNorm < 240) [r, g, b] = [0, x, c]
63
+ else if (hNorm < 300) [r, g, b] = [x, 0, c]
64
+ else [r, g, b] = [c, 0, x]
65
+
66
+ const toHex = (n: number) => Math.round((n + m) * 255).toString(16).padStart(2, '0')
67
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`
68
+ }
69
+
70
+ /**
71
+ * Derive a same-hue-family shade of `parentHex` for child at `index` of `total`.
72
+ *
73
+ * Lightness is distributed evenly within [35, 75] so all children remain
74
+ * readable on light/dark backgrounds. Hue and saturation are inherited from
75
+ * the parent. With `total <= 1`, returns the parent unchanged.
76
+ *
77
+ * Children are ordered light → dark by index, so index 0 is the brightest
78
+ * sibling and index `total - 1` is the darkest.
79
+ */
80
+ export function deriveShade(parentHex: string, index: number, total: number): string {
81
+ if (total <= 1) return parentHex
82
+ const { h, s, l } = hexToHsl(parentHex)
83
+
84
+ const L_MIN = 35
85
+ const L_MAX = 75
86
+ const spread = Math.min(L_MAX - L_MIN, 40)
87
+ const center = clamp(l, L_MIN + spread / 2, L_MAX - spread / 2)
88
+
89
+ const top = center + spread / 2
90
+ const bot = center - spread / 2
91
+ const t = total === 1 ? 0.5 : index / (total - 1)
92
+ const childL = top - t * (top - bot)
93
+
94
+ const childS = clamp(s, 35, 100)
95
+ return hslToHex(h, childS, childL)
96
+ }