@morscherlab/mint-sdk 1.0.0-rc.2 → 1.0.0-rc.5

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 (443) hide show
  1. package/dist/__tests__/components/AppTopBar.navigation.test.d.ts +1 -0
  2. package/dist/__tests__/components/DoseCalculatorVolumeField.test.d.ts +1 -0
  3. package/dist/__tests__/components/PlateMapEditorToolbarInternal.test.d.ts +1 -0
  4. package/dist/__tests__/components/PluginWorkspaceView.controls.test.d.ts +1 -0
  5. package/dist/__tests__/components/PluginWorkspaceView.navigation.test.d.ts +1 -0
  6. package/dist/__tests__/components/PluginWorkspaceView.shell.test.d.ts +1 -0
  7. package/dist/__tests__/components/ProtocolStep.presentation.test.d.ts +1 -0
  8. package/dist/__tests__/components/ProtocolStepEditor.state.test.d.ts +1 -0
  9. package/dist/__tests__/components/ProtocolStepParameterField.test.d.ts +1 -0
  10. package/dist/__tests__/components/ReagentList.presentation.test.d.ts +1 -0
  11. package/dist/__tests__/components/SampleSelector.colors.test.d.ts +1 -0
  12. package/dist/__tests__/components/SampleSelector.drag.test.d.ts +1 -0
  13. package/dist/__tests__/components/SampleSelector.groups.test.d.ts +1 -0
  14. package/dist/__tests__/components/SampleSelector.selection.test.d.ts +1 -0
  15. package/dist/__tests__/components/SampleSelectorSampleRow.test.d.ts +1 -0
  16. package/dist/__tests__/components/ScheduleCalendar.test.d.ts +1 -0
  17. package/dist/__tests__/components/SettingsModal.schema.test.d.ts +1 -0
  18. package/dist/__tests__/components/WellPlate.colors.test.d.ts +1 -0
  19. package/dist/__tests__/components/WellPlate.conditions.test.d.ts +1 -0
  20. package/dist/__tests__/components/WellPlate.geometry.test.d.ts +1 -0
  21. package/dist/__tests__/components/WellPlate.interaction.test.d.ts +1 -0
  22. package/dist/__tests__/components/WellPlate.legend.test.d.ts +1 -0
  23. package/dist/__tests__/components/WellPlate.rendering.test.d.ts +1 -0
  24. package/dist/__tests__/components/WellPlate.sampleDrop.test.d.ts +1 -0
  25. package/dist/__tests__/composables/autoGroup/classify.test.d.ts +1 -0
  26. package/dist/__tests__/composables/autoGroup/columns.test.d.ts +1 -0
  27. package/dist/__tests__/composables/autoGroup/compose.test.d.ts +1 -0
  28. package/dist/__tests__/composables/autoGroup/cooccurrence.test.d.ts +1 -0
  29. package/dist/__tests__/composables/autoGroup/fingerprint.test.d.ts +1 -0
  30. package/dist/__tests__/composables/autoGroup/integration.test.d.ts +1 -0
  31. package/dist/__tests__/composables/autoGroup/template.test.d.ts +1 -0
  32. package/dist/__tests__/composables/autoGroup/tokenize.test.d.ts +1 -0
  33. package/dist/__tests__/composables/useAutoGroupInputSources.test.d.ts +1 -0
  34. package/dist/__tests__/composables/useScheduleCalendarLayout.test.d.ts +1 -0
  35. package/dist/__tests__/docs/extractDocsComponents.test.d.ts +1 -0
  36. package/dist/__tests__/docs/extractDocsExports.test.d.ts +1 -0
  37. package/dist/__tests__/docs/extractDocsParsing.test.d.ts +1 -0
  38. package/dist/__tests__/docs/extractDocsTemplates.test.d.ts +1 -0
  39. package/dist/__tests__/docs/extractDocsTheme.test.d.ts +1 -0
  40. package/dist/components/AppTopBar.navigation.d.ts +11 -0
  41. package/dist/components/BaseButton.vue.d.ts +1 -1
  42. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  43. package/dist/components/BaseInput.vue.d.ts +2 -2
  44. package/dist/components/BasePill.vue.d.ts +1 -1
  45. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  46. package/dist/components/BaseSelect.vue.d.ts +1 -1
  47. package/dist/components/BaseSlider.vue.d.ts +2 -2
  48. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  49. package/dist/components/BaseToggle.vue.d.ts +1 -1
  50. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  51. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  52. package/dist/components/ColorSlider.vue.d.ts +2 -2
  53. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  54. package/dist/components/DatePicker.vue.d.ts +1 -1
  55. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  56. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  57. package/dist/components/DropdownButton.vue.d.ts +1 -1
  58. package/dist/components/FileUploader.vue.d.ts +2 -2
  59. package/dist/components/FormulaInput.vue.d.ts +2 -2
  60. package/dist/components/IconButton.vue.d.ts +1 -1
  61. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  62. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  63. package/dist/components/MultiSelect.vue.d.ts +1 -1
  64. package/dist/components/NumberInput.vue.d.ts +1 -1
  65. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  66. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  67. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  68. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  69. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  70. package/dist/components/PluginWorkspaceView.vue.d.ts +46 -195
  71. package/dist/components/ProgressBar.vue.d.ts +1 -1
  72. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  73. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  74. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  75. package/dist/components/ReagentList.presentation.d.ts +16 -0
  76. package/dist/components/ResourceCard.vue.d.ts +1 -1
  77. package/dist/components/SampleSelector.colors.d.ts +13 -0
  78. package/dist/components/SampleSelector.drag.d.ts +24 -0
  79. package/dist/components/SampleSelector.groups.d.ts +15 -0
  80. package/dist/components/SampleSelector.selection.d.ts +26 -0
  81. package/dist/components/SampleSelector.vue.d.ts +4 -1
  82. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  83. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  84. package/dist/components/SequenceInput.vue.d.ts +2 -2
  85. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  86. package/dist/components/SettingsModal.schema.d.ts +9 -0
  87. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  88. package/dist/components/TagsInput.vue.d.ts +2 -2
  89. package/dist/components/TimePicker.vue.d.ts +2 -2
  90. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  91. package/dist/components/UnitInput.vue.d.ts +2 -2
  92. package/dist/components/WellPlate.colors.d.ts +9 -0
  93. package/dist/components/WellPlate.conditions.d.ts +26 -0
  94. package/dist/components/WellPlate.geometry.d.ts +23 -0
  95. package/dist/components/WellPlate.interaction.d.ts +71 -0
  96. package/dist/components/WellPlate.legend.d.ts +2 -0
  97. package/dist/components/WellPlate.rendering.d.ts +24 -0
  98. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  99. package/dist/components/WellPlate.vue.d.ts +1 -1
  100. package/dist/components/index.js +2 -2
  101. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  102. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  103. package/dist/{components-BhK-dW99.js → components-DtHA2bgp.js} +3754 -2991
  104. package/dist/components-DtHA2bgp.js.map +1 -0
  105. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  106. package/dist/composables/autoGroup/classify.d.ts +28 -0
  107. package/dist/composables/autoGroup/colors.d.ts +2 -0
  108. package/dist/composables/autoGroup/columns.d.ts +10 -0
  109. package/dist/composables/autoGroup/compose.d.ts +8 -0
  110. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  111. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  112. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  113. package/dist/composables/autoGroup/index.d.ts +16 -0
  114. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  115. package/dist/composables/autoGroup/template.d.ts +15 -0
  116. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  117. package/dist/composables/autoGroupConstants.d.ts +1 -0
  118. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  119. package/dist/composables/controlComponentBindings.d.ts +7 -0
  120. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  121. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  122. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  123. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  124. package/dist/composables/controlSchemaModel.d.ts +5 -0
  125. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  126. package/dist/composables/controlSchemaTypes.d.ts +305 -0
  127. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  128. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  129. package/dist/composables/formBuilderSchema.d.ts +18 -0
  130. package/dist/composables/index.js +3 -3
  131. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  132. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  133. package/dist/composables/useAutoGroup.d.ts +61 -74
  134. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  135. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  136. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  137. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  138. package/dist/composables/useControlSchema.d.ts +8 -346
  139. package/dist/composables/useControlWorkspace.d.ts +5 -0
  140. package/dist/composables/useForm.d.ts +2 -33
  141. package/dist/composables/useFormBuilder.d.ts +2 -9
  142. package/dist/composables/useFormValidation.d.ts +34 -0
  143. package/dist/composables/usePluginClient.d.ts +1 -4
  144. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  145. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  146. package/dist/{composables-Bg7CFuNz.js → composables-Dlg8jenH.js} +33 -31
  147. package/dist/composables-Dlg8jenH.js.map +1 -0
  148. package/dist/index.js +4 -4
  149. package/dist/install.js +2 -2
  150. package/dist/styles.css +547 -516
  151. package/dist/templates/adapters.d.ts +14 -47
  152. package/dist/templates/assayLookups.d.ts +3 -0
  153. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  154. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  155. package/dist/templates/assayNormalizers.d.ts +4 -0
  156. package/dist/templates/builderDefaults.d.ts +1 -0
  157. package/dist/templates/builderIdUtils.d.ts +4 -0
  158. package/dist/templates/builderPresetControls.d.ts +10 -0
  159. package/dist/templates/builderReadUtils.d.ts +8 -0
  160. package/dist/templates/builders.d.ts +26 -67
  161. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  162. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  163. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  164. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  165. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  166. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  167. package/dist/templates/componentGenericProps.d.ts +8 -0
  168. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  169. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  170. package/dist/templates/componentPropsFactory.d.ts +3 -0
  171. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  172. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  173. package/dist/templates/componentTemplateProps.d.ts +3 -0
  174. package/dist/templates/controlSchemaClone.d.ts +4 -0
  175. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  176. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  177. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  178. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  179. package/dist/templates/controlSchemas.d.ts +4 -4
  180. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  181. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  182. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  183. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  184. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  185. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  186. package/dist/templates/flowNormalizers.d.ts +8 -0
  187. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  188. package/dist/templates/index.js +1 -1
  189. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  190. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  191. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  192. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  193. package/dist/templates/plateGeometry.d.ts +4 -0
  194. package/dist/templates/plateMapAdapters.d.ts +3 -0
  195. package/dist/templates/plateMapBuilder.d.ts +2 -0
  196. package/dist/templates/presetControlSchemas.d.ts +534 -0
  197. package/dist/templates/protocolAdapters.d.ts +5 -0
  198. package/dist/templates/protocolNormalizers.d.ts +6 -0
  199. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  200. package/dist/templates/qpcrAdapters.d.ts +5 -0
  201. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  202. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  203. package/dist/templates/reagentAdapters.d.ts +5 -0
  204. package/dist/templates/reagentListBuilder.d.ts +2 -0
  205. package/dist/templates/runNormalizers.d.ts +10 -0
  206. package/dist/templates/sampleNormalizers.d.ts +4 -0
  207. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  208. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  209. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  210. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  211. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  212. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  213. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  214. package/dist/templates/templateControlSchemas.d.ts +400 -0
  215. package/dist/templates/templateCreateOptions.d.ts +165 -0
  216. package/dist/templates/templateEnvelopes.d.ts +9 -0
  217. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  218. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  219. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  220. package/dist/templates/templateValidators.d.ts +13 -0
  221. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  222. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  223. package/dist/templates/types.d.ts +5 -250
  224. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  225. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  226. package/dist/{templates-BorLR_7p.js → templates-DtdUvJ4c.js} +3565 -3411
  227. package/dist/templates-DtdUvJ4c.js.map +1 -0
  228. package/dist/types/auto-group.d.ts +79 -9
  229. package/dist/types/componentLabTypes.d.ts +161 -0
  230. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  231. package/dist/types/components.d.ts +2 -311
  232. package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-Bm5vyH4_.js} +1220 -454
  233. package/dist/useProtocolTemplates-Bm5vyH4_.js.map +1 -0
  234. package/package.json +1 -1
  235. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  236. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  237. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  238. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  239. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  240. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +41 -0
  241. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  242. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  243. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  244. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  245. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  246. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  247. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  248. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  249. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  250. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  251. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  252. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  253. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  254. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  255. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  256. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  257. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  258. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  259. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  260. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  261. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  262. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  263. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  264. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  265. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  266. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  267. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  268. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  269. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  270. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  271. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  272. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  273. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  274. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  275. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  276. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  277. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  278. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  279. package/src/components/AppSidebar.vue +2 -6
  280. package/src/components/AppTopBar.navigation.ts +62 -0
  281. package/src/components/AppTopBar.vue +17 -44
  282. package/src/components/AutoGroupModal.story.vue +50 -0
  283. package/src/components/AutoGroupModal.vue +441 -158
  284. package/src/components/ControlWorkspaceView.vue +2 -6
  285. package/src/components/DoseCalculator.vue +13 -73
  286. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  287. package/src/components/ExperimentTimeline.vue +6 -31
  288. package/src/components/FormBuilder.vue +2 -7
  289. package/src/components/PlateMapEditor.vue +32 -106
  290. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  291. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  292. package/src/components/PluginWorkspaceView.props.ts +174 -0
  293. package/src/components/PluginWorkspaceView.shell.ts +66 -0
  294. package/src/components/PluginWorkspaceView.vue +85 -404
  295. package/src/components/ProtocolStep.presentation.ts +31 -0
  296. package/src/components/ProtocolStepEditor.state.ts +104 -0
  297. package/src/components/ProtocolStepEditor.vue +48 -179
  298. package/src/components/ProtocolStepParameterField.vue +134 -0
  299. package/src/components/ReagentList.presentation.ts +105 -0
  300. package/src/components/ReagentList.vue +16 -79
  301. package/src/components/SampleSelector.colors.ts +43 -0
  302. package/src/components/SampleSelector.drag.ts +164 -0
  303. package/src/components/SampleSelector.groups.ts +109 -0
  304. package/src/components/SampleSelector.selection.ts +103 -0
  305. package/src/components/SampleSelector.vue +82 -349
  306. package/src/components/SampleSelectorSampleRow.vue +64 -0
  307. package/src/components/ScheduleCalendar.vue +44 -199
  308. package/src/components/SettingsModal.schema.ts +71 -0
  309. package/src/components/SettingsModal.vue +16 -46
  310. package/src/components/WellPlate.colors.ts +56 -0
  311. package/src/components/WellPlate.conditions.ts +100 -0
  312. package/src/components/WellPlate.geometry.ts +91 -0
  313. package/src/components/WellPlate.interaction.ts +272 -0
  314. package/src/components/WellPlate.legend.ts +8 -0
  315. package/src/components/WellPlate.rendering.ts +105 -0
  316. package/src/components/WellPlate.sampleDrop.ts +73 -0
  317. package/src/components/WellPlate.vue +102 -550
  318. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  319. package/src/composables/autoGroup/classKey.ts +5 -0
  320. package/src/composables/autoGroup/classify.ts +205 -0
  321. package/src/composables/autoGroup/colors.ts +6 -0
  322. package/src/composables/autoGroup/columns.ts +226 -0
  323. package/src/composables/autoGroup/compose.ts +156 -0
  324. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  325. package/src/composables/autoGroup/csv-shim.ts +44 -0
  326. package/src/composables/autoGroup/fingerprint.ts +49 -0
  327. package/src/composables/autoGroup/index.ts +20 -0
  328. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  329. package/src/composables/autoGroup/template.ts +126 -0
  330. package/src/composables/autoGroup/tokenize.ts +41 -0
  331. package/src/composables/autoGroup/vocab.json +67 -0
  332. package/src/composables/autoGroupConstants.ts +4 -0
  333. package/src/composables/autoGroupGrouping.ts +148 -0
  334. package/src/composables/controlComponentBindings.ts +80 -0
  335. package/src/composables/controlSchemaAdapters.ts +196 -0
  336. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  337. package/src/composables/controlSchemaFormFields.ts +61 -0
  338. package/src/composables/controlSchemaLayout.ts +59 -0
  339. package/src/composables/controlSchemaModel.ts +163 -0
  340. package/src/composables/controlSchemaNormalize.ts +101 -0
  341. package/src/composables/controlSchemaTypes.ts +364 -0
  342. package/src/composables/controlSchemaUtils.ts +36 -0
  343. package/src/composables/controlWorkspaceOptions.ts +21 -0
  344. package/src/composables/formBuilderSchema.ts +153 -0
  345. package/src/composables/pluginEndpointBuilder.ts +203 -0
  346. package/src/composables/protocolTemplateCatalog.ts +325 -0
  347. package/src/composables/useAutoGroup.ts +395 -549
  348. package/src/composables/useAutoGroupInputSources.ts +147 -0
  349. package/src/composables/useBioTemplateControls.ts +1 -1
  350. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  351. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  352. package/src/composables/useControlSchema.ts +64 -1312
  353. package/src/composables/useControlWorkspace.ts +201 -0
  354. package/src/composables/useForm.ts +5 -187
  355. package/src/composables/useFormBuilder.ts +11 -153
  356. package/src/composables/useFormValidation.ts +154 -0
  357. package/src/composables/usePluginClient.ts +10 -193
  358. package/src/composables/useProtocolTemplates.ts +10 -328
  359. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  360. package/src/styles/components/auto-group-modal.css +248 -310
  361. package/src/templates/adapters.ts +89 -930
  362. package/src/templates/assayLookups.ts +33 -0
  363. package/src/templates/assayMatrixAdapters.ts +78 -0
  364. package/src/templates/assayMatrixBuilder.ts +59 -0
  365. package/src/templates/assayNormalizers.ts +34 -0
  366. package/src/templates/builderDefaults.ts +11 -0
  367. package/src/templates/builderIdUtils.ts +20 -0
  368. package/src/templates/builderPresetControls.ts +165 -0
  369. package/src/templates/builderReadUtils.ts +57 -0
  370. package/src/templates/builders.ts +122 -2350
  371. package/src/templates/calibrationCurveAdapters.ts +59 -0
  372. package/src/templates/calibrationCurveBuilder.ts +99 -0
  373. package/src/templates/calibrationNormalizers.ts +60 -0
  374. package/src/templates/componentBindingCatalog.ts +90 -0
  375. package/src/templates/componentBindingHelpers.ts +93 -0
  376. package/src/templates/componentBindings.ts +12 -461
  377. package/src/templates/componentDoseResponseProps.ts +42 -0
  378. package/src/templates/componentGenericProps.ts +77 -0
  379. package/src/templates/componentPlateHelpers.ts +29 -0
  380. package/src/templates/componentPlateMapProps.ts +32 -0
  381. package/src/templates/componentPropsFactory.ts +21 -0
  382. package/src/templates/componentQpcrPlateProps.ts +28 -0
  383. package/src/templates/componentTargetResolvers.ts +69 -0
  384. package/src/templates/componentTemplateProps.ts +78 -0
  385. package/src/templates/controlSchemaClone.ts +32 -0
  386. package/src/templates/controlSchemaConstants.ts +11 -0
  387. package/src/templates/controlSchemaMerge.ts +40 -0
  388. package/src/templates/controlSchemaTargets.ts +87 -0
  389. package/src/templates/controlSchemaTypes.ts +20 -0
  390. package/src/templates/controlSchemas.ts +22 -704
  391. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  392. package/src/templates/doseResponseAdapters.ts +45 -0
  393. package/src/templates/doseResponseBuilder.ts +44 -0
  394. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  395. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  396. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  397. package/src/templates/flowNormalizers.ts +58 -0
  398. package/src/templates/flowPanelAdapters.ts +58 -0
  399. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  400. package/src/templates/instrumentRunAdapters.ts +163 -0
  401. package/src/templates/instrumentRunBuilder.ts +97 -0
  402. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  403. package/src/templates/plateGeometry.ts +62 -0
  404. package/src/templates/plateMapAdapters.ts +36 -0
  405. package/src/templates/plateMapBuilder.ts +43 -0
  406. package/src/templates/presetControlSchemas.ts +258 -0
  407. package/src/templates/protocolAdapters.ts +69 -0
  408. package/src/templates/protocolNormalizers.ts +37 -0
  409. package/src/templates/protocolStepsBuilder.ts +36 -0
  410. package/src/templates/qpcrAdapters.ts +104 -0
  411. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  412. package/src/templates/qpcrPlateBuilder.ts +96 -0
  413. package/src/templates/reagentAdapters.ts +77 -0
  414. package/src/templates/reagentListBuilder.ts +30 -0
  415. package/src/templates/runNormalizers.ts +63 -0
  416. package/src/templates/sampleNormalizers.ts +58 -0
  417. package/src/templates/samplePrepAdapters.ts +63 -0
  418. package/src/templates/samplePrepBuilder.ts +51 -0
  419. package/src/templates/sampleSheetAdapters.ts +75 -0
  420. package/src/templates/sampleSheetBuilder.ts +23 -0
  421. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  422. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  423. package/src/templates/templateAdapterTypes.ts +58 -0
  424. package/src/templates/templateControlSchemas.ts +320 -0
  425. package/src/templates/templateCreateOptions.ts +208 -0
  426. package/src/templates/templateEnvelopes.ts +137 -0
  427. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  428. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  429. package/src/templates/templateQpcrTypes.ts +48 -0
  430. package/src/templates/templateValidators.ts +414 -0
  431. package/src/templates/timeCourseAdapters.ts +73 -0
  432. package/src/templates/timeCourseBuilder.ts +64 -0
  433. package/src/templates/types.ts +79 -275
  434. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  435. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  436. package/src/types/auto-group.ts +107 -9
  437. package/src/types/componentLabTypes.ts +235 -0
  438. package/src/types/componentWorkflowTypes.ts +190 -0
  439. package/src/types/components.ts +74 -424
  440. package/dist/components-BhK-dW99.js.map +0 -1
  441. package/dist/composables-Bg7CFuNz.js.map +0 -1
  442. package/dist/templates-BorLR_7p.js.map +0 -1
  443. package/dist/useProtocolTemplates-n6AJqSqv.js.map +0 -1
@@ -4,6 +4,34 @@ import { ref, computed } from 'vue'
4
4
  import type { WellPlateFormat, WellPlateSelectionMode, WellPlateSize, Well, HeatmapConfig, WellShape, WellEditField, WellEditData, WellLegendItem, ColumnCondition, RowCondition, WellSampleDropData, WellSampleDropParser } from '../types'
5
5
  import { useEventListener } from '../composables/useEventListener'
6
6
  import WellEditPopupInternal from './internal/WellEditPopupInternal.vue'
7
+ import {
8
+ conditionGradientStyle,
9
+ formatConcentration as formatConc,
10
+ HEATMAP_COLORS,
11
+ } from './WellPlate.colors'
12
+ import {
13
+ createColumnConditionMap,
14
+ createColumnConditionSpans,
15
+ createRowConditionMap,
16
+ createRowConditionSpanByRow,
17
+ createRowConditionSpans,
18
+ } from './WellPlate.conditions'
19
+ import {
20
+ createPlateColumnLabels,
21
+ createPlateRowLabels,
22
+ createWellGrid,
23
+ PLATE_CONFIGS,
24
+ WELL_PLATE_SIZE_CONFIGS,
25
+ } from './WellPlate.geometry'
26
+ import { useWellPlateInteraction } from './WellPlate.interaction'
27
+ import {
28
+ sampleTypeIndicator,
29
+ wellBadge,
30
+ wellClasses,
31
+ wellLabel,
32
+ wellStyle,
33
+ } from './WellPlate.rendering'
34
+ import { DEFAULT_WELL_LEGEND_ITEMS } from './WellPlate.legend'
7
35
 
8
36
  interface Props {
9
37
  modelValue?: string[]
@@ -33,10 +61,6 @@ interface Props {
33
61
  sampleDropParser?: WellSampleDropParser
34
62
  }
35
63
 
36
- // Drag state for moving wells
37
- const dragSourceWell = ref<string | null>(null)
38
- const dragTargetWell = ref<string | null>(null)
39
-
40
64
  const props = withDefaults(defineProps<Props>(), {
41
65
  modelValue: () => [],
42
66
  format: 96,
@@ -94,581 +118,109 @@ defineSlots<{
94
118
 
95
119
  const plateRef = ref<HTMLElement | null>(null)
96
120
  const tableRef = ref<HTMLElement | null>(null)
97
- const isDragging = ref(false)
98
- const dragStart = ref<{ row: number; col: number } | null>(null)
99
- const dragEnd = ref<{ row: number; col: number } | null>(null)
100
- const hoveredWell = ref<string | null>(null)
101
-
102
- // Edit popup state
103
- const editingWellId = ref<string | null>(null)
104
- const editPopupPosition = ref({ x: 0, y: 0 })
105
-
106
- const PLATE_CONFIGS: Record<WellPlateFormat, { rows: number; cols: number }> = {
107
- 6: { rows: 2, cols: 3 },
108
- 12: { rows: 3, cols: 4 },
109
- 24: { rows: 4, cols: 6 },
110
- 48: { rows: 6, cols: 8 },
111
- 54: { rows: 6, cols: 9 },
112
- 96: { rows: 8, cols: 12 },
113
- 384: { rows: 16, cols: 24 },
114
- }
115
121
 
116
122
  const plateConfig = computed(() => PLATE_CONFIGS[props.format])
117
123
 
118
- const rowLabels = computed(() =>
119
- Array.from({ length: plateConfig.value.rows }, (_, i) => String.fromCharCode(65 + i))
120
- )
121
-
122
- const colLabels = computed(() =>
123
- Array.from({ length: plateConfig.value.cols }, (_, i) => i + 1)
124
- )
125
-
126
- const wellGrid = computed(() => {
127
- const grid: Well[][] = []
128
- for (let row = 0; row < plateConfig.value.rows; row++) {
129
- const rowWells: Well[] = []
130
- for (let col = 0; col < plateConfig.value.cols; col++) {
131
- const id = `${rowLabels.value[row]}${col + 1}`
132
- const wellData = props.wells[id] || {}
133
- rowWells.push({
134
- id,
135
- row,
136
- col,
137
- state: wellData.state || 'empty',
138
- sampleType: wellData.sampleType,
139
- value: wellData.value,
140
- metadata: wellData.metadata,
141
- })
142
- }
143
- grid.push(rowWells)
144
- }
145
- return grid
146
- })
147
-
148
- const selectedWellSet = computed(() => new Set(props.modelValue))
124
+ const rowLabels = computed(() => createPlateRowLabels(plateConfig.value))
149
125
 
150
- const dragSelectedWells = computed(() => {
151
- if (!isDragging.value || !dragStart.value || !dragEnd.value) return new Set<string>()
126
+ const colLabels = computed(() => createPlateColumnLabels(plateConfig.value))
152
127
 
153
- const minRow = Math.min(dragStart.value.row, dragEnd.value.row)
154
- const maxRow = Math.max(dragStart.value.row, dragEnd.value.row)
155
- const minCol = Math.min(dragStart.value.col, dragEnd.value.col)
156
- const maxCol = Math.max(dragStart.value.col, dragEnd.value.col)
128
+ const wellGrid = computed(() => createWellGrid(plateConfig.value, rowLabels.value, props.wells))
157
129
 
158
- const wells = new Set<string>()
159
- for (let row = minRow; row <= maxRow; row++) {
160
- for (let col = minCol; col <= maxCol; col++) {
161
- const id = `${rowLabels.value[row]}${col + 1}`
162
- wells.add(id)
163
- }
164
- }
165
- return wells
166
- })
167
-
168
- // Size presets with pixel values for reliable sizing
169
- const sizeConfig = computed(() => {
170
- const sizes = {
171
- sm: { cellWidth: '40px', cellHeight: '40px', headerWidth: '32px', headerHeight: '32px', fontSize: '0.625rem', gap: '2px' },
172
- md: { cellWidth: '56px', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '3px' },
173
- lg: { cellWidth: '80px', cellHeight: '40px', headerWidth: '40px', headerHeight: '32px', fontSize: '0.875rem', gap: '4px' },
174
- xl: { cellWidth: '96px', cellHeight: '48px', headerWidth: '48px', headerHeight: '40px', fontSize: '1rem', gap: '4px' },
175
- fill: { cellWidth: '100%', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '2px' },
176
- }
177
- return sizes[props.size]
178
- })
130
+ const sizeConfig = computed(() => WELL_PLATE_SIZE_CONFIGS[props.size])
179
131
 
180
132
  const isFillMode = computed(() => props.size === 'fill')
181
133
 
182
- // Default legend items
183
- const defaultLegendItems: WellLegendItem[] = [
184
- { type: 'sample', label: 'Sample', color: '#10b981' },
185
- { type: 'blank', label: 'Blank', color: '#f97316' },
186
- { type: 'qc', label: 'QC', color: '#8b5cf6' },
187
- { type: 'iqc', label: 'IQC', color: '#ec4899' },
188
- ]
189
-
190
- const activeLegendItems = computed(() => props.legendItems ?? defaultLegendItems)
134
+ const activeLegendItems = computed(() => props.legendItems ?? DEFAULT_WELL_LEGEND_ITEMS)
191
135
 
192
136
  // --- Condition header helpers ---
193
137
 
194
138
  const hasColumnConditions = computed(() => props.columnConditions.length > 0)
195
139
  const hasRowConditions = computed(() => props.rowConditions.length > 0)
196
140
 
197
- // Map column index (1-based) ColumnCondition
198
- const colConditionMap = computed(() => {
199
- const map = new Map<number, { condition: ColumnCondition; indexInGroup: number }>()
200
- for (const cond of props.columnConditions) {
201
- cond.cols.forEach((col, i) => {
202
- map.set(col, { condition: cond, indexInGroup: i })
203
- })
204
- }
205
- return map
141
+ const colConditionMap = computed(() => createColumnConditionMap(props.columnConditions))
142
+ const rowConditionMap = computed(() => createRowConditionMap(props.rowConditions))
143
+ const colConditionSpans = computed(() => createColumnConditionSpans(colLabels.value, colConditionMap.value))
144
+ const rowConditionSpans = computed(() => createRowConditionSpans(rowLabels.value, rowConditionMap.value))
145
+ const rowConditionSpanByRow = computed(() => createRowConditionSpanByRow(rowConditionSpans.value))
146
+
147
+ const {
148
+ dragSourceWell,
149
+ dragTargetWell,
150
+ hoveredWell,
151
+ editingWellId,
152
+ editPopupPosition,
153
+ dragSelectedWells,
154
+ isSelected,
155
+ handleWellClick,
156
+ handleEditSave,
157
+ handleEditClear,
158
+ handleEditClose,
159
+ handleWellMouseDown,
160
+ handleWellMouseEnter,
161
+ handleWellMouseLeave,
162
+ handleMouseUp,
163
+ handleContextMenu,
164
+ handleDragStart,
165
+ handleDragOver,
166
+ handleDragLeave,
167
+ handleDrop,
168
+ handleDragEnd,
169
+ handleKeyDown,
170
+ } = useWellPlateInteraction({
171
+ modelValue: () => props.modelValue,
172
+ selectionMode: () => props.selectionMode,
173
+ disabled: () => props.disabled,
174
+ readonly: () => props.readonly,
175
+ editable: () => props.editable,
176
+ allowSampleDrop: () => props.allowSampleDrop,
177
+ sampleDropParser: () => props.sampleDropParser,
178
+ rowLabels: () => rowLabels.value,
179
+ wellGrid: () => wellGrid.value,
180
+ emitSelected: (wellIds) => {
181
+ emit('update:modelValue', wellIds)
182
+ emit('selection-change', wellIds)
183
+ },
184
+ emitWellClick: (wellId, event) => emit('well-click', wellId, event),
185
+ emitWellHover: (wellId, event) => emit('well-hover', wellId, event),
186
+ emitContextMenu: (wellId, event) => emit('context-menu', wellId, event),
187
+ emitWellMove: (sourceWellId, targetWellId) => emit('well-move', sourceWellId, targetWellId),
188
+ emitWellEdit: (wellId, data) => emit('well-edit', wellId, data),
189
+ emitWellClear: wellId => emit('well-clear', wellId),
190
+ emitSampleDrop: (wellId, data, event) => emit('sample-drop', wellId, data, event),
206
191
  })
207
192
 
208
- // Map row letter → RowCondition
209
- const rowConditionMap = computed(() => {
210
- const map = new Map<string, { condition: RowCondition; indexInGroup: number }>()
211
- for (const cond of props.rowConditions) {
212
- cond.rows.forEach((row, i) => {
213
- map.set(row, { condition: cond, indexInGroup: i })
214
- })
215
- }
216
- return map
217
- })
218
-
219
- type ColSpan = { condition: ColumnCondition; colspan: number } | { gap: true; colspan: number }
220
- type RowSpan = { condition: RowCondition; rowspan: number; startRow: number } | { gap: true; rowspan: number; startRow: number }
221
-
222
- // Build column condition header spans for the label row (drug name + unit)
223
- const colConditionSpans = computed<ColSpan[]>(() => {
224
- const spans: ColSpan[] = []
225
- const cols = colLabels.value
226
- let i = 0
227
- while (i < cols.length) {
228
- const entry = colConditionMap.value.get(cols[i])
229
- if (entry?.indexInGroup === 0) {
230
- spans.push({ condition: entry.condition, colspan: entry.condition.cols.length })
231
- i += entry.condition.cols.length
232
- } else {
233
- let gapCount = 0
234
- while (i + gapCount < cols.length && !colConditionMap.value.has(cols[i + gapCount])) {
235
- gapCount++
236
- }
237
- spans.push({ gap: true, colspan: gapCount || 1 })
238
- i += gapCount || 1
239
- }
240
- }
241
- return spans
242
- })
243
-
244
- // Build row condition spans for the label column (drug name rotated)
245
- const rowConditionSpans = computed<RowSpan[]>(() => {
246
- const spans: RowSpan[] = []
247
- const rows = rowLabels.value
248
- let i = 0
249
- while (i < rows.length) {
250
- const entry = rowConditionMap.value.get(rows[i])
251
- if (entry?.indexInGroup === 0) {
252
- spans.push({ condition: entry.condition, rowspan: entry.condition.rows.length, startRow: i })
253
- i += entry.condition.rows.length
254
- } else {
255
- let gapCount = 0
256
- while (i + gapCount < rows.length && !rowConditionMap.value.has(rows[i + gapCount])) {
257
- gapCount++
258
- }
259
- spans.push({ gap: true, rowspan: gapCount || 1, startRow: i })
260
- i += gapCount || 1
261
- }
262
- }
263
- return spans
264
- })
265
-
266
- // Map row index → span info (only contains entries for first row of each span)
267
- const rowConditionSpanByRow = computed(() => {
268
- const map = new Map<number, RowSpan>()
269
- for (const span of rowConditionSpans.value) {
270
- map.set(span.startRow, span)
271
- }
272
- return map
273
- })
274
-
275
- // Compute gradient style for a condition cell: background opacity scales with concentration,
276
- // text color adapts based on effective luminance against white background
277
- function conditionGradientStyle(color: string, conc: number, concentrations: number[]): Record<string, string> {
278
- const min = Math.min(...concentrations)
279
- const max = Math.max(...concentrations)
280
- const t = max <= min ? 1 : (conc - min) / (max - min)
281
- const opacity = 0.25 + t * 0.50
282
- const r = parseInt(color.slice(1, 3), 16)
283
- const g = parseInt(color.slice(3, 5), 16)
284
- const b = parseInt(color.slice(5, 7), 16)
285
- // Blend with white to get effective RGB, then compute relative luminance
286
- const er = 255 * (1 - opacity) + r * opacity
287
- const eg = 255 * (1 - opacity) + g * opacity
288
- const eb = 255 * (1 - opacity) + b * opacity
289
- const luminance = (0.299 * er + 0.587 * eg + 0.114 * eb) / 255
290
- return {
291
- backgroundColor: `rgba(${r}, ${g}, ${b}, ${opacity})`,
292
- color: luminance > 0.55 ? '#1e293b' : '#ffffff',
293
- }
294
- }
295
-
296
- // Format concentration value (drop trailing zeros)
297
- function formatConc(value: number): string {
298
- if (value >= 1000) return `${value / 1000}k`
299
- if (value < 0.01) return value.toExponential(0)
300
- return String(value)
301
- }
302
-
303
- // Sample type colors (matching MSExpDesigner)
304
- const defaultSampleTypeColors: Record<string, { bg: string; border: string }> = {
305
- sample: { bg: 'rgba(16, 185, 129, 0.15)', border: 'rgba(16, 185, 129, 0.4)' },
306
- control: { bg: 'rgba(59, 130, 246, 0.15)', border: 'rgba(59, 130, 246, 0.4)' },
307
- blank: { bg: 'rgba(249, 115, 22, 0.15)', border: 'rgba(249, 115, 22, 0.4)' },
308
- qc: { bg: 'rgba(139, 92, 246, 0.15)', border: 'rgba(139, 92, 246, 0.4)' },
309
- iqc: { bg: 'rgba(236, 72, 153, 0.15)', border: 'rgba(236, 72, 153, 0.4)' },
310
- }
311
-
312
- const heatmapColors: Record<string, string[]> = {
313
- viridis: ['#440154', '#482878', '#3e4989', '#31688e', '#26828e', '#1f9e89', '#35b779', '#6ece58', '#b5de2b', '#fde725'],
314
- plasma: ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'],
315
- turbo: ['#30123b', '#4145ab', '#4675ed', '#39a2fc', '#1bcfd4', '#24e79e', '#71f05f', '#c1f034', '#f1c83c', '#f99538', '#e45a31', '#ba2512', '#7a0403'],
316
- }
317
-
318
- function getHeatmapColor(value: number | undefined): string | null {
319
- if (!props.heatmap?.enabled || value === undefined) return null
320
-
321
- const min = props.heatmap.min ?? 0
322
- const max = props.heatmap.max ?? 1
323
- const normalized = Math.max(0, Math.min(1, (value - min) / (max - min)))
324
-
325
- const colors = props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length
326
- ? props.heatmap.customColors
327
- : heatmapColors[props.heatmap.colorScale || 'viridis']
328
-
329
- const index = Math.min(Math.floor(normalized * (colors.length - 1)), colors.length - 1)
330
- return colors[index]
331
- }
332
-
333
193
  function getWellClasses(well: Well): string[] {
334
- const isWellSelected = isSelected(well.id)
335
- const isDragOver = dragSelectedWells.value.has(well.id)
336
- const isHovered = hoveredWell.value === well.id
337
- const isDisabled = props.disabled || well.state === 'disabled'
338
- const isDragSource = dragSourceWell.value === well.id
339
- const isDragTarget = dragTargetWell.value === well.id
340
-
341
- const classes = [
342
- 'mint-well-plate__well',
343
- props.wellShape === 'circle' ? 'mint-well-plate__well--circle' : 'mint-well-plate__well--rounded',
344
- ]
345
-
346
- if (props.selectionMode === 'drag' && well.sampleType) {
347
- classes.push('mint-well-plate__well--draggable')
348
- }
349
-
350
- if (isDragSource) classes.push('mint-well-plate__well--drag-source')
351
- else if (isDragTarget) classes.push('mint-well-plate__well--drag-target')
352
- else if (isWellSelected) classes.push('mint-well-plate__well--selected')
353
- else if (isDragOver) classes.push('mint-well-plate__well--drag-over')
354
- else if (isHovered && !props.readonly) classes.push('mint-well-plate__well--hovered')
355
-
356
- if (isDisabled) classes.push('mint-well-plate__well--disabled')
357
- if (well.state === 'filled') classes.push('mint-well-plate__well--filled')
358
-
359
- return classes
194
+ return wellClasses(well, {
195
+ wellShape: props.wellShape,
196
+ selectionMode: props.selectionMode,
197
+ selected: isSelected(well.id),
198
+ dragOver: dragSelectedWells.value.has(well.id),
199
+ hovered: hoveredWell.value === well.id,
200
+ disabled: props.disabled || well.state === 'disabled',
201
+ readonly: props.readonly,
202
+ dragSource: dragSourceWell.value === well.id,
203
+ dragTarget: dragTargetWell.value === well.id,
204
+ })
360
205
  }
361
206
 
362
207
  function getWellStyle(well: Well): Record<string, string> {
363
- const heatmapColor = getHeatmapColor(well.value)
364
- if (heatmapColor) {
365
- return { backgroundColor: heatmapColor, border: '1px solid transparent' }
366
- }
367
-
368
- if (well.sampleType && props.sampleColors[well.sampleType]) {
369
- const color = props.sampleColors[well.sampleType]
370
- return {
371
- backgroundColor: `${color}26`,
372
- border: `1px solid ${color}66`,
373
- }
374
- }
375
-
376
- if (well.sampleType && defaultSampleTypeColors[well.sampleType]) {
377
- const colors = defaultSampleTypeColors[well.sampleType]
378
- return {
379
- backgroundColor: colors.bg,
380
- border: `1px solid ${colors.border}`,
381
- }
382
- }
383
-
384
- const borderStyle = well.state === 'filled' ? 'solid' : 'dashed'
385
- return {
386
- backgroundColor: 'var(--bg-tertiary)',
387
- border: `1px ${borderStyle} var(--border-color)`,
388
- }
208
+ return wellStyle(well, {
209
+ heatmap: props.heatmap,
210
+ sampleColors: props.sampleColors,
211
+ })
389
212
  }
390
213
 
391
214
  function getSampleTypeIndicator(well: Well): string | null {
392
- if (!props.showSampleTypeIndicator || !well.sampleType) return null
393
- const typeMap: Record<string, string> = {
394
- sample: 'S',
395
- control: 'C',
396
- blank: 'B',
397
- qc: 'Q',
398
- iqc: 'I',
399
- }
400
- return typeMap[well.sampleType] || well.sampleType.charAt(0).toUpperCase()
215
+ return sampleTypeIndicator(well, props.showSampleTypeIndicator)
401
216
  }
402
217
 
403
218
  function getWellLabel(well: Well): string | undefined {
404
- if (!props.showWellLabels) return undefined
405
- return well.metadata?.label as string | undefined
219
+ return wellLabel(well, props.showWellLabels)
406
220
  }
407
221
 
408
222
  function getWellBadge(well: Well): { text: string; color: string } | null {
409
- if (!props.showBadges || !well.metadata) return null
410
- const count = well.metadata.injectionCount as number | undefined
411
- if (count && count > 1) {
412
- return { text: String(count), color: '#6366f1' }
413
- }
414
- if (well.metadata.customMethod) {
415
- return { text: '+', color: '#ec4899' }
416
- }
417
- return null
418
- }
419
-
420
- function isSelected(wellId: string): boolean {
421
- return selectedWellSet.value.has(wellId) || dragSelectedWells.value.has(wellId)
422
- }
423
-
424
- function handleWellClick(well: Well, event: MouseEvent) {
425
- if (props.disabled || props.readonly) return
426
-
427
- emit('well-click', well.id, event)
428
-
429
- // When editable, open popup instead of modifying selection
430
- if (props.editable) {
431
- openEditPopup(well.id, event)
432
- return
433
- }
434
-
435
- if (props.selectionMode === 'none') return
436
-
437
- const isCurrentlySelected = selectedWellSet.value.has(well.id)
438
- const isMultiSelect = event.shiftKey || event.metaKey || event.ctrlKey
439
-
440
- let newSelection: string[]
441
- if (props.selectionMode === 'single') {
442
- newSelection = isCurrentlySelected ? [] : [well.id]
443
- } else if (isMultiSelect) {
444
- newSelection = isCurrentlySelected
445
- ? props.modelValue.filter(id => id !== well.id)
446
- : [...props.modelValue, well.id]
447
- } else {
448
- newSelection = isCurrentlySelected && props.modelValue.length === 1 ? [] : [well.id]
449
- }
450
-
451
- emit('update:modelValue', newSelection)
452
- emit('selection-change', newSelection)
453
- }
454
-
455
- function openEditPopup(wellId: string, event: MouseEvent) {
456
- const target = event.currentTarget as HTMLElement
457
- const rect = target.getBoundingClientRect()
458
- editPopupPosition.value = {
459
- x: rect.right + 8,
460
- y: rect.top,
461
- }
462
- editingWellId.value = wellId
463
- }
464
-
465
- function handleEditSave(data: WellEditData) {
466
- emit('well-edit', data.wellId, data)
467
- editingWellId.value = null
468
- }
469
-
470
- function handleEditClear() {
471
- if (editingWellId.value) {
472
- emit('well-clear', editingWellId.value)
473
- }
474
- editingWellId.value = null
475
- }
476
-
477
- function handleEditClose() {
478
- editingWellId.value = null
479
- }
480
-
481
- function handleWellMouseDown(well: Well, event: MouseEvent) {
482
- if (props.disabled || props.readonly || props.selectionMode !== 'rectangle') return
483
- if (props.editable) return
484
- if (event.button !== 0) return
485
-
486
- isDragging.value = true
487
- dragStart.value = { row: well.row, col: well.col }
488
- dragEnd.value = { row: well.row, col: well.col }
489
- }
490
-
491
- function handleWellMouseEnter(well: Well, event: MouseEvent) {
492
- hoveredWell.value = well.id
493
- emit('well-hover', well.id, event)
494
-
495
- if (isDragging.value && props.selectionMode === 'rectangle') {
496
- dragEnd.value = { row: well.row, col: well.col }
497
- }
498
- }
499
-
500
- function handleWellMouseLeave() {
501
- hoveredWell.value = null
502
- emit('well-hover', null)
503
- }
504
-
505
- function handleMouseUp() {
506
- if (!isDragging.value || props.selectionMode !== 'rectangle') return
507
-
508
- const newSelection = Array.from(dragSelectedWells.value)
509
- isDragging.value = false
510
- dragStart.value = null
511
- dragEnd.value = null
512
-
513
- if (newSelection.length > 0) {
514
- emit('update:modelValue', newSelection)
515
- emit('selection-change', newSelection)
516
- }
517
- }
518
-
519
- function handleContextMenu(well: Well, event: MouseEvent) {
520
- event.preventDefault()
521
- emit('context-menu', well.id, event)
522
- }
523
-
524
- // Drag handlers for moving well contents
525
- function handleDragStart(well: Well, event: DragEvent) {
526
- if (props.disabled || props.readonly || props.selectionMode !== 'drag') return
527
- if (!well.sampleType) return
528
-
529
- dragSourceWell.value = well.id
530
- if (event.dataTransfer) {
531
- event.dataTransfer.effectAllowed = 'move'
532
- event.dataTransfer.setData('text/plain', well.id)
533
- }
534
- }
535
-
536
- function handleDragOver(well: Well, event: DragEvent) {
537
- const isMovingWell = props.selectionMode === 'drag' && !!dragSourceWell.value
538
- if (!isMovingWell && !props.allowSampleDrop) return
539
-
540
- event.preventDefault()
541
- if (event.dataTransfer) {
542
- event.dataTransfer.dropEffect = isMovingWell ? 'move' : 'copy'
543
- }
544
- dragTargetWell.value = well.id
545
- }
546
-
547
- function handleDragLeave() {
548
- dragTargetWell.value = null
549
- }
550
-
551
- function handleDrop(well: Well, event: DragEvent) {
552
- const isMovingWell = props.selectionMode === 'drag' && !!dragSourceWell.value
553
- if (!isMovingWell && !props.allowSampleDrop) return
554
-
555
- event.preventDefault()
556
-
557
- if (isMovingWell && dragSourceWell.value) {
558
- const sourceId = dragSourceWell.value
559
- const targetId = well.id
560
-
561
- if (sourceId !== targetId) {
562
- emit('well-move', sourceId, targetId)
563
- }
564
-
565
- dragSourceWell.value = null
566
- dragTargetWell.value = null
567
- return
568
- }
569
-
570
- const droppedSample = parseDroppedSample(event, well.id)
571
- if (droppedSample) {
572
- emit('sample-drop', well.id, droppedSample, event)
573
- }
574
-
575
- dragSourceWell.value = null
576
- dragTargetWell.value = null
577
- }
578
-
579
- function handleDragEnd() {
580
- dragSourceWell.value = null
581
- dragTargetWell.value = null
582
- }
583
-
584
- function parseDroppedSample(event: DragEvent, wellId: string): WellSampleDropData | null {
585
- if (props.sampleDropParser) {
586
- return props.sampleDropParser(event, { wellId, event }) ?? null
587
- }
588
-
589
- const transfer = event.dataTransfer
590
- if (!transfer) return null
591
-
592
- const json = transfer.getData('application/json') || transfer.getData('text/json')
593
- if (json) {
594
- try {
595
- return normalizeDroppedSample(JSON.parse(json))
596
- } catch {
597
- return null
598
- }
599
- }
600
-
601
- const text = transfer.getData('text/plain')?.trim()
602
- if (!text) return null
603
- return {
604
- sampleName: text,
605
- label: text,
606
- raw: text,
607
- }
608
- }
609
-
610
- function normalizeDroppedSample(raw: unknown): WellSampleDropData | null {
611
- if (!raw || typeof raw !== 'object') return null
612
-
613
- const record = raw as Record<string, unknown>
614
- const sampleName =
615
- getString(record.sampleName) ??
616
- getString(record.sample_name) ??
617
- getString(record.name) ??
618
- getString(record.label)
619
- const label = getString(record.label) ?? sampleName
620
- const sampleType =
621
- getString(record.sampleType) ??
622
- getString(record.sample_type) ??
623
- (record.type === 'sample' ? 'sample' : undefined)
624
-
625
- if (!sampleName && !label && !getString(record.id)) return null
626
-
627
- return {
628
- id: getString(record.id),
629
- sampleName,
630
- label,
631
- sampleType,
632
- injectionVolume: getNumber(record.injectionVolume ?? record.injection_volume),
633
- injectionCount: getNumber(record.injectionCount ?? record.injection_count),
634
- customMethod: getString(record.customMethod ?? record.custom_method) ?? null,
635
- metadata: getRecord(record.metadata),
636
- raw,
637
- }
638
- }
639
-
640
- function getString(value: unknown): string | undefined {
641
- return typeof value === 'string' && value.trim() ? value.trim() : undefined
642
- }
643
-
644
- function getNumber(value: unknown): number | undefined {
645
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined
646
- }
647
-
648
- function getRecord(value: unknown): Record<string, unknown> | undefined {
649
- return value && typeof value === 'object' && !Array.isArray(value)
650
- ? value as Record<string, unknown>
651
- : undefined
652
- }
653
-
654
- function handleKeyDown(event: KeyboardEvent) {
655
- if (props.disabled || props.readonly) return
656
-
657
- if (event.key === 'Escape') {
658
- if (editingWellId.value) {
659
- editingWellId.value = null
660
- return
661
- }
662
- emit('update:modelValue', [])
663
- emit('selection-change', [])
664
- }
665
-
666
- if ((event.key === 'a' || event.key === 'A') && (event.metaKey || event.ctrlKey)) {
667
- event.preventDefault()
668
- const allWells = wellGrid.value.flat().map(w => w.id)
669
- emit('update:modelValue', allWells)
670
- emit('selection-change', allWells)
671
- }
223
+ return wellBadge(well, props.showBadges)
672
224
  }
673
225
 
674
226
  useEventListener(() => document, 'mouseup', handleMouseUp)
@@ -886,7 +438,7 @@ const tableStyle = computed(() => ({
886
438
  <span class="mint-well-plate__legend-label">{{ props.heatmap.min ?? 0 }}</span>
887
439
  <div class="mint-well-plate__legend-bar">
888
440
  <div
889
- v-for="(color, index) in (props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length ? props.heatmap.customColors : heatmapColors[props.heatmap.colorScale || 'viridis'])"
441
+ v-for="(color, index) in (props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length ? props.heatmap.customColors : HEATMAP_COLORS[props.heatmap.colorScale || 'viridis'])"
890
442
  :key="index"
891
443
  class="mint-well-plate__legend-segment"
892
444
  :style="{ backgroundColor: color }"