@morscherlab/mint-sdk 1.0.0-rc.4 → 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 (304) 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/AppSidebar.vue.d.ts +3 -3
  41. package/dist/components/AppTopBar.navigation.d.ts +11 -0
  42. package/dist/components/BaseButton.vue.d.ts +1 -1
  43. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  44. package/dist/components/BaseInput.vue.d.ts +2 -2
  45. package/dist/components/BasePill.vue.d.ts +1 -1
  46. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  47. package/dist/components/BaseSelect.vue.d.ts +1 -1
  48. package/dist/components/BaseSlider.vue.d.ts +2 -2
  49. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  50. package/dist/components/BaseToggle.vue.d.ts +1 -1
  51. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  52. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  53. package/dist/components/ColorSlider.vue.d.ts +2 -2
  54. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  55. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  56. package/dist/components/DatePicker.vue.d.ts +1 -1
  57. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  58. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  59. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
  60. package/dist/components/DropdownButton.vue.d.ts +1 -1
  61. package/dist/components/FileUploader.vue.d.ts +2 -2
  62. package/dist/components/FormulaInput.vue.d.ts +2 -2
  63. package/dist/components/IconButton.vue.d.ts +1 -1
  64. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  65. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  66. package/dist/components/MultiSelect.vue.d.ts +1 -1
  67. package/dist/components/NumberInput.vue.d.ts +1 -1
  68. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  69. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  70. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  71. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  72. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  73. package/dist/components/PluginWorkspaceView.vue.d.ts +46 -195
  74. package/dist/components/ProgressBar.vue.d.ts +1 -1
  75. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  76. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  77. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  78. package/dist/components/ReagentList.presentation.d.ts +16 -0
  79. package/dist/components/ResourceCard.vue.d.ts +1 -1
  80. package/dist/components/SampleSelector.colors.d.ts +13 -0
  81. package/dist/components/SampleSelector.drag.d.ts +24 -0
  82. package/dist/components/SampleSelector.groups.d.ts +15 -0
  83. package/dist/components/SampleSelector.selection.d.ts +26 -0
  84. package/dist/components/SampleSelector.vue.d.ts +4 -1
  85. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  86. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  87. package/dist/components/SequenceInput.vue.d.ts +2 -2
  88. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  89. package/dist/components/SettingsModal.schema.d.ts +9 -0
  90. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  91. package/dist/components/TagsInput.vue.d.ts +2 -2
  92. package/dist/components/TimePicker.vue.d.ts +2 -2
  93. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  94. package/dist/components/UnitInput.vue.d.ts +2 -2
  95. package/dist/components/WellPlate.colors.d.ts +9 -0
  96. package/dist/components/WellPlate.conditions.d.ts +26 -0
  97. package/dist/components/WellPlate.geometry.d.ts +23 -0
  98. package/dist/components/WellPlate.interaction.d.ts +71 -0
  99. package/dist/components/WellPlate.legend.d.ts +2 -0
  100. package/dist/components/WellPlate.rendering.d.ts +24 -0
  101. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  102. package/dist/components/WellPlate.vue.d.ts +1 -1
  103. package/dist/components/index.js +2 -2
  104. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  105. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  106. package/dist/{components-DafPc4rM.js → components-DtHA2bgp.js} +3754 -2991
  107. package/dist/components-DtHA2bgp.js.map +1 -0
  108. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  109. package/dist/composables/autoGroup/classify.d.ts +28 -0
  110. package/dist/composables/autoGroup/colors.d.ts +2 -0
  111. package/dist/composables/autoGroup/columns.d.ts +10 -0
  112. package/dist/composables/autoGroup/compose.d.ts +8 -0
  113. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  114. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  115. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  116. package/dist/composables/autoGroup/index.d.ts +16 -0
  117. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  118. package/dist/composables/autoGroup/template.d.ts +15 -0
  119. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  120. package/dist/composables/autoGroupConstants.d.ts +1 -0
  121. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  122. package/dist/composables/controlComponentBindings.d.ts +1 -1
  123. package/dist/composables/controlSchemaAdapters.d.ts +1 -1
  124. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  125. package/dist/composables/controlSchemaLayout.d.ts +1 -1
  126. package/dist/composables/controlSchemaModel.d.ts +5 -0
  127. package/dist/composables/controlSchemaNormalize.d.ts +1 -1
  128. package/dist/composables/controlSchemaTypes.d.ts +305 -0
  129. package/dist/composables/controlWorkspaceOptions.d.ts +1 -1
  130. package/dist/composables/formBuilderSchema.d.ts +18 -0
  131. package/dist/composables/index.js +3 -3
  132. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  133. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  134. package/dist/composables/useAutoGroup.d.ts +61 -74
  135. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  136. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  137. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  138. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  139. package/dist/composables/useControlSchema.d.ts +4 -316
  140. package/dist/composables/useControlWorkspace.d.ts +1 -1
  141. package/dist/composables/useForm.d.ts +2 -33
  142. package/dist/composables/useFormBuilder.d.ts +2 -9
  143. package/dist/composables/useFormValidation.d.ts +34 -0
  144. package/dist/composables/usePluginClient.d.ts +1 -4
  145. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  146. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  147. package/dist/{composables-BMkPQhVK.js → composables-Dlg8jenH.js} +33 -31
  148. package/dist/composables-Dlg8jenH.js.map +1 -0
  149. package/dist/index.js +4 -4
  150. package/dist/install.js +2 -2
  151. package/dist/styles.css +547 -516
  152. package/dist/templates/controlSchemaTypes.d.ts +1 -1
  153. package/dist/templates/index.js +1 -1
  154. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  155. package/dist/templates/templateCreateOptions.d.ts +165 -0
  156. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  157. package/dist/templates/types.d.ts +5 -250
  158. package/dist/{templates-bUAWMn5L.js → templates-DtdUvJ4c.js} +144 -136
  159. package/dist/templates-DtdUvJ4c.js.map +1 -0
  160. package/dist/types/auto-group.d.ts +79 -9
  161. package/dist/types/componentLabTypes.d.ts +161 -0
  162. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  163. package/dist/types/components.d.ts +2 -311
  164. package/dist/{useProtocolTemplates-QZtHFFH2.js → useProtocolTemplates-Bm5vyH4_.js} +1220 -454
  165. package/dist/useProtocolTemplates-Bm5vyH4_.js.map +1 -0
  166. package/package.json +1 -1
  167. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  168. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  169. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  170. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  171. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  172. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +41 -0
  173. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  174. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  175. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  176. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  177. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  178. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  179. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  180. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  181. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  182. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  183. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  184. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  185. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  186. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  187. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  188. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  189. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  190. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  191. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  192. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  193. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  194. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  195. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  196. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  197. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  198. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  199. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  200. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  201. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  202. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  203. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  204. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  205. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  206. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  207. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  208. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  209. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  210. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  211. package/src/components/AppSidebar.vue +2 -6
  212. package/src/components/AppTopBar.navigation.ts +62 -0
  213. package/src/components/AppTopBar.vue +17 -44
  214. package/src/components/AutoGroupModal.story.vue +50 -0
  215. package/src/components/AutoGroupModal.vue +441 -158
  216. package/src/components/ControlWorkspaceView.vue +2 -6
  217. package/src/components/DoseCalculator.vue +13 -73
  218. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  219. package/src/components/ExperimentTimeline.vue +6 -31
  220. package/src/components/FormBuilder.vue +2 -7
  221. package/src/components/PlateMapEditor.vue +32 -106
  222. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  223. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  224. package/src/components/PluginWorkspaceView.props.ts +174 -0
  225. package/src/components/PluginWorkspaceView.shell.ts +66 -0
  226. package/src/components/PluginWorkspaceView.vue +85 -404
  227. package/src/components/ProtocolStep.presentation.ts +31 -0
  228. package/src/components/ProtocolStepEditor.state.ts +104 -0
  229. package/src/components/ProtocolStepEditor.vue +48 -179
  230. package/src/components/ProtocolStepParameterField.vue +134 -0
  231. package/src/components/ReagentList.presentation.ts +105 -0
  232. package/src/components/ReagentList.vue +16 -79
  233. package/src/components/SampleSelector.colors.ts +43 -0
  234. package/src/components/SampleSelector.drag.ts +164 -0
  235. package/src/components/SampleSelector.groups.ts +109 -0
  236. package/src/components/SampleSelector.selection.ts +103 -0
  237. package/src/components/SampleSelector.vue +82 -349
  238. package/src/components/SampleSelectorSampleRow.vue +64 -0
  239. package/src/components/ScheduleCalendar.vue +44 -199
  240. package/src/components/SettingsModal.schema.ts +71 -0
  241. package/src/components/SettingsModal.vue +16 -46
  242. package/src/components/WellPlate.colors.ts +56 -0
  243. package/src/components/WellPlate.conditions.ts +100 -0
  244. package/src/components/WellPlate.geometry.ts +91 -0
  245. package/src/components/WellPlate.interaction.ts +272 -0
  246. package/src/components/WellPlate.legend.ts +8 -0
  247. package/src/components/WellPlate.rendering.ts +105 -0
  248. package/src/components/WellPlate.sampleDrop.ts +73 -0
  249. package/src/components/WellPlate.vue +102 -550
  250. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  251. package/src/composables/autoGroup/classKey.ts +5 -0
  252. package/src/composables/autoGroup/classify.ts +205 -0
  253. package/src/composables/autoGroup/colors.ts +6 -0
  254. package/src/composables/autoGroup/columns.ts +226 -0
  255. package/src/composables/autoGroup/compose.ts +156 -0
  256. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  257. package/src/composables/autoGroup/csv-shim.ts +44 -0
  258. package/src/composables/autoGroup/fingerprint.ts +49 -0
  259. package/src/composables/autoGroup/index.ts +20 -0
  260. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  261. package/src/composables/autoGroup/template.ts +126 -0
  262. package/src/composables/autoGroup/tokenize.ts +41 -0
  263. package/src/composables/autoGroup/vocab.json +67 -0
  264. package/src/composables/autoGroupConstants.ts +4 -0
  265. package/src/composables/autoGroupGrouping.ts +148 -0
  266. package/src/composables/controlComponentBindings.ts +1 -1
  267. package/src/composables/controlSchemaAdapters.ts +1 -1
  268. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  269. package/src/composables/controlSchemaFormFields.ts +1 -1
  270. package/src/composables/controlSchemaLayout.ts +1 -1
  271. package/src/composables/controlSchemaModel.ts +163 -0
  272. package/src/composables/controlSchemaNormalize.ts +1 -1
  273. package/src/composables/controlSchemaTypes.ts +364 -0
  274. package/src/composables/controlWorkspaceOptions.ts +1 -1
  275. package/src/composables/formBuilderSchema.ts +153 -0
  276. package/src/composables/pluginEndpointBuilder.ts +203 -0
  277. package/src/composables/protocolTemplateCatalog.ts +325 -0
  278. package/src/composables/useAutoGroup.ts +395 -549
  279. package/src/composables/useAutoGroupInputSources.ts +147 -0
  280. package/src/composables/useBioTemplateControls.ts +1 -1
  281. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  282. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  283. package/src/composables/useControlSchema.ts +21 -692
  284. package/src/composables/useControlWorkspace.ts +7 -13
  285. package/src/composables/useForm.ts +5 -187
  286. package/src/composables/useFormBuilder.ts +11 -153
  287. package/src/composables/useFormValidation.ts +154 -0
  288. package/src/composables/usePluginClient.ts +10 -193
  289. package/src/composables/useProtocolTemplates.ts +10 -328
  290. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  291. package/src/styles/components/auto-group-modal.css +248 -310
  292. package/src/templates/controlSchemaTypes.ts +1 -1
  293. package/src/templates/templateAdapterTypes.ts +58 -0
  294. package/src/templates/templateCreateOptions.ts +208 -0
  295. package/src/templates/templateQpcrTypes.ts +48 -0
  296. package/src/templates/types.ts +79 -275
  297. package/src/types/auto-group.ts +107 -9
  298. package/src/types/componentLabTypes.ts +235 -0
  299. package/src/types/componentWorkflowTypes.ts +190 -0
  300. package/src/types/components.ts +74 -424
  301. package/dist/components-DafPc4rM.js.map +0 -1
  302. package/dist/composables-BMkPQhVK.js.map +0 -1
  303. package/dist/templates-bUAWMn5L.js.map +0 -1
  304. package/dist/useProtocolTemplates-QZtHFFH2.js.map +0 -1
@@ -4,14 +4,26 @@ import { ref, computed } from 'vue'
4
4
  import BaseButton from './BaseButton.vue'
5
5
  import BaseInput from './BaseInput.vue'
6
6
  import AutoGroupModal from './AutoGroupModal.vue'
7
+ import SampleSelectorSampleRow from './SampleSelectorSampleRow.vue'
7
8
  import type { SampleGroup } from '../types'
8
9
  import type { AutoGroupResult } from '../types/auto-group'
9
- import { DEFAULT_COLORS } from '../composables/useAutoGroup'
10
10
  import { useTextSearch } from '../composables/useTextSearch'
11
- import { useListSelection } from '../composables/useListSelection'
12
11
  import { useSampleGroups, type SampleMajorGroup } from '../composables/useSampleGroups'
13
12
  import { useExpansionSet } from '../composables/useExpansionSet'
14
13
  import { useExperimentSamples } from '../composables/useExperimentSamples'
14
+ import { useSampleSelectorDrag } from './SampleSelector.drag'
15
+ import { useSampleSelectorSelection } from './SampleSelector.selection'
16
+ import {
17
+ applySampleGroupColorEdit,
18
+ createSampleGroup,
19
+ getSampleGroupColorEditSeed,
20
+ type ColorEdit,
21
+ } from './SampleSelector.colors'
22
+ import {
23
+ removeSampleFromGroup as removeSampleFromSampleGroup,
24
+ removeSampleGroup,
25
+ removeSampleMajorGroup,
26
+ } from './SampleSelector.groups'
15
27
 
16
28
  interface Props {
17
29
  samples?: string[]
@@ -41,10 +53,6 @@ const emit = defineEmits<{
41
53
  }>()
42
54
 
43
55
  // UI State
44
- type ColorEdit =
45
- | { kind: 'single'; name: string }
46
- | { kind: 'family'; names: string[] }
47
-
48
56
  const showSmartGroupModal = ref(false)
49
57
  const newGroupName = ref('')
50
58
  const editingColor = ref<ColorEdit | null>(null)
@@ -52,24 +60,31 @@ const colorPickerInput = ref<HTMLInputElement | null>(null)
52
60
  const searchQuery = ref('')
53
61
  const groupExpansion = useExpansionSet()
54
62
 
55
- // Sample Drag State
56
- const draggingSample = ref<string | null>(null)
57
- const dragSourceGroup = ref<string | null>(null)
58
- const dragOverGroup = ref<string | null>(null)
59
-
60
- // Group-Reorder Drag State
61
- type GroupDragKind = 'major' | 'sub' | 'flat'
62
- const draggingGroup = ref<string | null>(null)
63
- const draggingGroupKind = ref<GroupDragKind | null>(null)
64
- const reorderTarget = ref<string | null>(null)
65
- const reorderPosition = ref<'before' | 'after' | null>(null)
66
-
67
63
  // Computed: groups from props
68
64
  const internalGroups = computed({
69
65
  get: () => props.groups,
70
66
  set: (value) => emit('update:groups', value),
71
67
  })
72
68
 
69
+ const {
70
+ draggingSample,
71
+ dragOverGroup,
72
+ draggingGroup,
73
+ draggingGroupKind,
74
+ reorderTarget,
75
+ reorderPosition,
76
+ handleDragStart,
77
+ handleDragEnd,
78
+ handleDragOver,
79
+ handleDragLeave,
80
+ handleDrop,
81
+ handleGroupDragStart,
82
+ handleGroupDragEnd,
83
+ handleGroupDragOver,
84
+ handleGroupDragLeave,
85
+ handleGroupDrop,
86
+ } = useSampleSelectorDrag(internalGroups)
87
+
73
88
  const providedSamples = computed(() => props.samples)
74
89
  const shouldLoadExperimentSamples = computed(() =>
75
90
  props.autoloadExperimentData && providedSamples.value.length === 0,
@@ -102,61 +117,22 @@ const sampleSearch = useTextSearch({
102
117
  })
103
118
  const filteredSamples = sampleSearch.filteredItems
104
119
 
105
- const sampleSelection = useListSelection({
120
+ const {
121
+ isAllSelected,
122
+ toggleSelectAll,
123
+ toggleSample,
124
+ toggleGroupSamples,
125
+ toggleMajorGroupSamples,
126
+ isGroupFullySelected,
127
+ isGroupPartiallySelected,
128
+ isMajorGroupFullySelected,
129
+ isMajorGroupPartiallySelected,
130
+ } = useSampleSelectorSelection({
106
131
  selected: () => props.modelValue,
107
- items: () => resolvedSamples.value,
132
+ samples: () => resolvedSamples.value,
133
+ findGroup: sampleGroups.findGroup,
134
+ emitSelected: samples => emit('update:modelValue', samples),
108
135
  })
109
- const isAllSelected = sampleSelection.isAllSelected
110
-
111
- // Toggle functions
112
- function toggleSelectAll() {
113
- emit('update:modelValue', sampleSelection.toggleAll())
114
- }
115
-
116
- function toggleSample(sample: string) {
117
- emit('update:modelValue', sampleSelection.toggleValue(sample))
118
- }
119
-
120
- function toggleSamplesSelection(samples: string[]) {
121
- emit('update:modelValue', sampleSelection.toggleValues(samples))
122
- }
123
-
124
- function toggleGroupSamples(groupName: string) {
125
- const group = sampleGroups.findGroup(groupName)
126
- if (!group) return
127
- toggleSamplesSelection(group.samples)
128
- }
129
-
130
- function toggleMajorGroupSamples(majorGroup: SampleMajorGroup) {
131
- toggleSamplesSelection(majorGroup.allSamples)
132
- }
133
-
134
- // Selection state checks
135
- function isFullySelected(samples: string[]): boolean {
136
- return sampleSelection.isFullySelected(samples)
137
- }
138
-
139
- function isPartiallySelected(samples: string[]): boolean {
140
- return sampleSelection.isPartiallySelected(samples)
141
- }
142
-
143
- function isGroupFullySelected(groupName: string): boolean {
144
- const group = sampleGroups.findGroup(groupName)
145
- return group ? isFullySelected(group.samples) : false
146
- }
147
-
148
- function isGroupPartiallySelected(groupName: string): boolean {
149
- const group = sampleGroups.findGroup(groupName)
150
- return group ? isPartiallySelected(group.samples) : false
151
- }
152
-
153
- function isMajorGroupFullySelected(majorGroup: SampleMajorGroup): boolean {
154
- return isFullySelected(majorGroup.allSamples)
155
- }
156
-
157
- function isMajorGroupPartiallySelected(majorGroup: SampleMajorGroup): boolean {
158
- return isPartiallySelected(majorGroup.allSamples)
159
- }
160
136
 
161
137
  // Expand/collapse
162
138
  function toggleGroupExpanded(groupName: string) {
@@ -195,194 +171,15 @@ function clearGroups() {
195
171
  }
196
172
 
197
173
  function deleteMajorGroup(majorGroup: SampleMajorGroup) {
198
- internalGroups.value = internalGroups.value.filter(
199
- g => !majorGroup.subGroups.some(sg => sg.name === g.name)
200
- )
174
+ internalGroups.value = removeSampleMajorGroup(internalGroups.value, majorGroup)
201
175
  }
202
176
 
203
177
  function deleteGroup(groupName: string) {
204
- internalGroups.value = internalGroups.value.filter(g => g.name !== groupName)
178
+ internalGroups.value = removeSampleGroup(internalGroups.value, groupName)
205
179
  }
206
180
 
207
181
  function removeSampleFromGroup(sample: string, groupName: string) {
208
- internalGroups.value = internalGroups.value.map(g =>
209
- g.name === groupName
210
- ? { ...g, samples: g.samples.filter((s: string) => s !== sample) }
211
- : g
212
- )
213
- }
214
-
215
- // Drag and Drop handlers
216
- function handleDragStart(sample: string, sourceGroup: string | null, event: DragEvent) {
217
- draggingSample.value = sample
218
- dragSourceGroup.value = sourceGroup
219
- if (event.dataTransfer) {
220
- event.dataTransfer.effectAllowed = 'move'
221
- event.dataTransfer.setData('text/plain', sample)
222
- }
223
- }
224
-
225
- function resetDragState() {
226
- draggingSample.value = null
227
- dragSourceGroup.value = null
228
- dragOverGroup.value = null
229
- }
230
-
231
- function handleDragEnd() {
232
- resetDragState()
233
- }
234
-
235
- function handleDragOver(groupName: string, event: DragEvent) {
236
- // Only accept this drop target when a sample is being dragged; group drags are handled separately.
237
- if (!draggingSample.value) return
238
- event.preventDefault()
239
- if (event.dataTransfer) {
240
- event.dataTransfer.dropEffect = 'move'
241
- }
242
- dragOverGroup.value = groupName
243
- }
244
-
245
- function handleDragLeave() {
246
- dragOverGroup.value = null
247
- }
248
-
249
- function handleDrop(targetGroupName: string, event: DragEvent) {
250
- if (!draggingSample.value) return
251
- event.preventDefault()
252
-
253
- const sample = draggingSample.value
254
- const sourceGroup = dragSourceGroup.value
255
-
256
- if (sourceGroup === targetGroupName) {
257
- resetDragState()
258
- return
259
- }
260
-
261
- internalGroups.value = internalGroups.value.map(g => {
262
- if (sourceGroup && g.name === sourceGroup) {
263
- return { ...g, samples: g.samples.filter((s: string) => s !== sample) }
264
- }
265
- if (g.name === targetGroupName && !g.samples.includes(sample)) {
266
- return { ...g, samples: [...g.samples, sample] }
267
- }
268
- return g
269
- })
270
-
271
- resetDragState()
272
- }
273
-
274
- // Group reorder helpers
275
- function detectSeparator(groups: SampleGroup[]): string {
276
- return groups.some(g => g.name.includes('/')) ? '/' : '_'
277
- }
278
-
279
- function getMajorPrefix(groupName: string, separator: string): string {
280
- const parts = groupName.split(separator)
281
- return parts.length > 1 ? parts[0] : groupName
282
- }
283
-
284
- function handleGroupDragStart(name: string, kind: GroupDragKind, event: DragEvent) {
285
- draggingGroup.value = name
286
- draggingGroupKind.value = kind
287
- if (event.dataTransfer) {
288
- event.dataTransfer.effectAllowed = 'move'
289
- event.dataTransfer.setData('text/plain', `mint-group:${name}`)
290
- }
291
- }
292
-
293
- function handleGroupDragEnd() {
294
- draggingGroup.value = null
295
- draggingGroupKind.value = null
296
- reorderTarget.value = null
297
- reorderPosition.value = null
298
- }
299
-
300
- function handleGroupDragOver(name: string, kind: GroupDragKind, event: DragEvent) {
301
- if (!draggingGroup.value || draggingGroupKind.value !== kind) return
302
- if (draggingGroup.value === name) return
303
-
304
- // Sub-group reorder is restricted to siblings under the same major prefix —
305
- // crossing majors would silently rename the group, which is too magical.
306
- if (kind === 'sub') {
307
- const sep = detectSeparator(internalGroups.value)
308
- if (getMajorPrefix(draggingGroup.value, sep) !== getMajorPrefix(name, sep)) return
309
- }
310
-
311
- event.preventDefault()
312
- if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'
313
-
314
- const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()
315
- reorderTarget.value = name
316
- reorderPosition.value = event.clientY < rect.top + rect.height / 2 ? 'before' : 'after'
317
- }
318
-
319
- function handleGroupDragLeave(event: DragEvent) {
320
- const cur = event.currentTarget as HTMLElement
321
- const rel = event.relatedTarget as Node | null
322
- if (rel && cur.contains(rel)) return
323
- reorderTarget.value = null
324
- reorderPosition.value = null
325
- }
326
-
327
- function handleGroupDrop(name: string, kind: GroupDragKind, event: DragEvent) {
328
- if (!draggingGroup.value || draggingGroupKind.value !== kind) {
329
- handleGroupDragEnd()
330
- return
331
- }
332
- const position = reorderPosition.value
333
- if (!position || draggingGroup.value === name) {
334
- handleGroupDragEnd()
335
- return
336
- }
337
-
338
- event.preventDefault()
339
-
340
- if (kind === 'major') {
341
- moveMajorGroup(draggingGroup.value, name, position)
342
- } else {
343
- moveGroup(draggingGroup.value, name, position)
344
- }
345
-
346
- handleGroupDragEnd()
347
- }
348
-
349
- function moveGroup(source: string, target: string, position: 'before' | 'after') {
350
- if (source === target) return
351
- const groups = [...internalGroups.value]
352
- const srcIdx = groups.findIndex(g => g.name === source)
353
- if (srcIdx === -1) return
354
- const [item] = groups.splice(srcIdx, 1)
355
- const targetIdx = groups.findIndex(g => g.name === target)
356
- if (targetIdx === -1) return
357
- groups.splice(position === 'before' ? targetIdx : targetIdx + 1, 0, item)
358
- internalGroups.value = groups
359
- }
360
-
361
- function moveMajorGroup(source: string, target: string, position: 'before' | 'after') {
362
- if (source === target) return
363
- const groups = [...internalGroups.value]
364
- const sep = detectSeparator(groups)
365
-
366
- const isSource = (g: SampleGroup) => getMajorPrefix(g.name, sep) === source
367
- const isTarget = (g: SampleGroup) => getMajorPrefix(g.name, sep) === target
368
-
369
- const sourceGroups = groups.filter(isSource)
370
- if (sourceGroups.length === 0) return
371
- const remaining = groups.filter(g => !isSource(g))
372
-
373
- let firstTarget = -1
374
- let lastTarget = -1
375
- remaining.forEach((g, i) => {
376
- if (isTarget(g)) {
377
- if (firstTarget === -1) firstTarget = i
378
- lastTarget = i
379
- }
380
- })
381
- if (firstTarget === -1) return
382
-
383
- const insertIdx = position === 'before' ? firstTarget : lastTarget + 1
384
- remaining.splice(insertIdx, 0, ...sourceGroups)
385
- internalGroups.value = remaining
182
+ internalGroups.value = removeSampleFromSampleGroup(internalGroups.value, sample, groupName)
386
183
  }
387
184
 
388
185
  // Color picker
@@ -403,12 +200,7 @@ function handleColorChange(event: Event) {
403
200
  if (!edit) return
404
201
 
405
202
  const newColor = (event.target as HTMLInputElement).value
406
- // For a family edit, every sub-group gets the new seed; the hierarchical
407
- // computed re-derives shades from it.
408
- const targets = edit.kind === 'family' ? new Set(edit.names) : new Set([edit.name])
409
- internalGroups.value = internalGroups.value.map(g =>
410
- targets.has(g.name) ? { ...g, color: newColor } : g,
411
- )
203
+ internalGroups.value = applySampleGroupColorEdit(internalGroups.value, edit, newColor)
412
204
  editingColor.value = null
413
205
  }
414
206
 
@@ -417,28 +209,18 @@ function getGroupColor(groupName: string): string {
417
209
  }
418
210
 
419
211
  const colorPickerSeed = computed(() => {
420
- const edit = editingColor.value
421
- if (!edit) return '#3B82F6'
422
- return getGroupColor(edit.kind === 'family' ? edit.names[0] : edit.name)
212
+ return getSampleGroupColorEditSeed(editingColor.value, getGroupColor)
423
213
  })
424
214
 
425
215
  // New group
426
216
  function addNewGroup() {
427
- if (!newGroupName.value.trim()) return
428
-
429
- const usedColors = new Set(internalGroups.value.map(g => g.color))
430
- const availableColor = DEFAULT_COLORS.find(c => !usedColors.has(c)) || DEFAULT_COLORS[0]
431
-
432
- const newGroup: SampleGroup = {
433
- name: newGroupName.value.trim(),
434
- color: availableColor,
435
- samples: [],
436
- }
437
-
217
+ const newGroup = createSampleGroup(newGroupName.value, internalGroups.value)
218
+ if (!newGroup) return
438
219
  internalGroups.value = [...internalGroups.value, newGroup]
439
220
  newGroupName.value = ''
440
221
  }
441
222
 
223
+ defineExpose({ handleSmartGroupApply })
442
224
  </script>
443
225
 
444
226
  <template>
@@ -670,39 +452,20 @@ function addNewGroup() {
670
452
  class="mint-sample-selector__samples"
671
453
  :style="{ borderColor: subGroup.displayBorder }"
672
454
  >
673
- <div
455
+ <SampleSelectorSampleRow
674
456
  v-for="sample in subGroup.samples"
675
457
  :key="sample"
676
- :class="[
677
- 'mint-sample-selector__sample',
678
- draggingSample === sample ? 'mint-sample-selector__sample--dragging' : '',
679
- ]"
680
- draggable="true"
458
+ :sample="sample"
459
+ :selected="modelValue.includes(sample)"
460
+ :dragging="draggingSample === sample"
461
+ :accent-color="subGroup.displayColor"
462
+ checkbox-size="tiny"
463
+ removable
681
464
  @dragstart="handleDragStart(sample, subGroup.name, $event)"
682
465
  @dragend="handleDragEnd"
683
- >
684
- <svg class="mint-sample-selector__drag-handle" fill="none" stroke="currentColor" viewBox="0 0 24 24">
685
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
686
- </svg>
687
- <input
688
- type="checkbox"
689
- :checked="modelValue.includes(sample)"
690
- class="mint-sample-selector__checkbox mint-sample-selector__checkbox--tiny"
691
- :style="{ accentColor: subGroup.displayColor }"
692
- @change="toggleSample(sample)"
693
- />
694
- <span class="mint-sample-selector__sample-name">{{ sample }}</span>
695
- <button
696
- type="button"
697
- class="mint-sample-selector__remove-btn"
698
- @click="removeSampleFromGroup(sample, subGroup.name)"
699
- title="Remove from group"
700
- >
701
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
702
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4" />
703
- </svg>
704
- </button>
705
- </div>
466
+ @toggle="toggleSample(sample)"
467
+ @remove="removeSampleFromGroup(sample, subGroup.name)"
468
+ />
706
469
  </div>
707
470
  </Transition>
708
471
  </div>
@@ -796,39 +559,20 @@ function addNewGroup() {
796
559
  class="mint-sample-selector__samples"
797
560
  :style="{ borderColor: group.color + '40' }"
798
561
  >
799
- <div
562
+ <SampleSelectorSampleRow
800
563
  v-for="sample in group.samples"
801
564
  :key="sample"
802
- :class="[
803
- 'mint-sample-selector__sample',
804
- draggingSample === sample ? 'mint-sample-selector__sample--dragging' : '',
805
- ]"
806
- draggable="true"
565
+ :sample="sample"
566
+ :selected="modelValue.includes(sample)"
567
+ :dragging="draggingSample === sample"
568
+ :accent-color="group.color"
569
+ checkbox-size="tiny"
570
+ removable
807
571
  @dragstart="handleDragStart(sample, group.name, $event)"
808
572
  @dragend="handleDragEnd"
809
- >
810
- <svg class="mint-sample-selector__drag-handle" fill="none" stroke="currentColor" viewBox="0 0 24 24">
811
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
812
- </svg>
813
- <input
814
- type="checkbox"
815
- :checked="modelValue.includes(sample)"
816
- class="mint-sample-selector__checkbox mint-sample-selector__checkbox--tiny"
817
- :style="{ accentColor: group.color }"
818
- @change="toggleSample(sample)"
819
- />
820
- <span class="mint-sample-selector__sample-name">{{ sample }}</span>
821
- <button
822
- type="button"
823
- class="mint-sample-selector__remove-btn"
824
- @click="removeSampleFromGroup(sample, group.name)"
825
- title="Remove from group"
826
- >
827
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
828
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4" />
829
- </svg>
830
- </button>
831
- </div>
573
+ @toggle="toggleSample(sample)"
574
+ @remove="removeSampleFromGroup(sample, group.name)"
575
+ />
832
576
  </div>
833
577
  </Transition>
834
578
  </div>
@@ -864,28 +608,17 @@ function addNewGroup() {
864
608
  v-if="isGroupExpanded('__ungrouped__')"
865
609
  class="mint-sample-selector__ungrouped-list"
866
610
  >
867
- <div
611
+ <SampleSelectorSampleRow
868
612
  v-for="sample in ungroupedSamples"
869
613
  :key="sample"
870
- :class="[
871
- 'mint-sample-selector__sample',
872
- draggingSample === sample ? 'mint-sample-selector__sample--dragging' : '',
873
- ]"
874
- draggable="true"
614
+ :sample="sample"
615
+ :selected="modelValue.includes(sample)"
616
+ :dragging="draggingSample === sample"
617
+ checkbox-size="small"
875
618
  @dragstart="handleDragStart(sample, null, $event)"
876
619
  @dragend="handleDragEnd"
877
- >
878
- <svg class="mint-sample-selector__drag-handle" fill="none" stroke="currentColor" viewBox="0 0 24 24">
879
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
880
- </svg>
881
- <input
882
- type="checkbox"
883
- :checked="modelValue.includes(sample)"
884
- class="mint-sample-selector__checkbox mint-sample-selector__checkbox--small"
885
- @change="toggleSample(sample)"
886
- />
887
- <span class="mint-sample-selector__sample-name">{{ sample }}</span>
888
- </div>
620
+ @toggle="toggleSample(sample)"
621
+ />
889
622
  </div>
890
623
  </Transition>
891
624
  </div>
@@ -0,0 +1,64 @@
1
+ <script setup lang="ts">
2
+ /** Single draggable sample row used by grouped and ungrouped SampleSelector lists. */
3
+ import { computed } from 'vue'
4
+
5
+ type CheckboxSize = 'small' | 'tiny'
6
+
7
+ interface Props {
8
+ sample: string
9
+ selected: boolean
10
+ dragging?: boolean
11
+ accentColor?: string
12
+ checkboxSize?: CheckboxSize
13
+ removable?: boolean
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ dragging: false,
18
+ checkboxSize: 'tiny',
19
+ removable: false,
20
+ })
21
+
22
+ const emit = defineEmits<{
23
+ toggle: []
24
+ remove: []
25
+ }>()
26
+
27
+ const checkboxClasses = computed(() => [
28
+ 'mint-sample-selector__checkbox',
29
+ `mint-sample-selector__checkbox--${props.checkboxSize}`,
30
+ ])
31
+ </script>
32
+
33
+ <template>
34
+ <div
35
+ :class="[
36
+ 'mint-sample-selector__sample',
37
+ dragging ? 'mint-sample-selector__sample--dragging' : '',
38
+ ]"
39
+ draggable="true"
40
+ >
41
+ <svg class="mint-sample-selector__drag-handle" fill="none" stroke="currentColor" viewBox="0 0 24 24">
42
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16" />
43
+ </svg>
44
+ <input
45
+ type="checkbox"
46
+ :checked="selected"
47
+ :class="checkboxClasses"
48
+ :style="accentColor ? { accentColor } : undefined"
49
+ @change="emit('toggle')"
50
+ />
51
+ <span class="mint-sample-selector__sample-name">{{ sample }}</span>
52
+ <button
53
+ v-if="removable"
54
+ type="button"
55
+ class="mint-sample-selector__remove-btn"
56
+ title="Remove from group"
57
+ @click="emit('remove')"
58
+ >
59
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
60
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4" />
61
+ </svg>
62
+ </button>
63
+ </div>
64
+ </template>