@morscherlab/mint-sdk 1.0.0-rc.4 → 1.0.0-rc.6

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 (324) 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 +9 -6
  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 +7 -2
  44. package/dist/components/BaseInput.vue.d.ts +2 -2
  45. package/dist/components/BasePill.vue.d.ts +2 -2
  46. package/dist/components/BaseRadioGroup.vue.d.ts +2 -2
  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 +7 -2
  51. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  52. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  53. package/dist/components/CollapsibleCard.vue.d.ts +9 -0
  54. package/dist/components/ColorSlider.vue.d.ts +2 -2
  55. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  56. package/dist/components/ControlWorkspaceView.vue.d.ts +4 -4
  57. package/dist/components/DatePicker.vue.d.ts +1 -1
  58. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  59. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  60. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +2 -2
  61. package/dist/components/DropdownButton.vue.d.ts +1 -1
  62. package/dist/components/FileUploader.vue.d.ts +2 -2
  63. package/dist/components/FormulaInput.vue.d.ts +2 -2
  64. package/dist/components/IconButton.vue.d.ts +1 -1
  65. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  66. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  67. package/dist/components/MultiSelect.vue.d.ts +1 -1
  68. package/dist/components/NumberInput.vue.d.ts +1 -1
  69. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  70. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  71. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  72. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  73. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  74. package/dist/components/PluginWorkspaceView.vue.d.ts +51 -196
  75. package/dist/components/ProgressBar.vue.d.ts +1 -1
  76. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  77. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  78. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  79. package/dist/components/ReagentList.presentation.d.ts +16 -0
  80. package/dist/components/ResourceCard.vue.d.ts +1 -1
  81. package/dist/components/SampleSelector.colors.d.ts +13 -0
  82. package/dist/components/SampleSelector.drag.d.ts +24 -0
  83. package/dist/components/SampleSelector.groups.d.ts +15 -0
  84. package/dist/components/SampleSelector.selection.d.ts +26 -0
  85. package/dist/components/SampleSelector.vue.d.ts +4 -1
  86. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  87. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  88. package/dist/components/SequenceInput.vue.d.ts +2 -2
  89. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  90. package/dist/components/SettingsModal.schema.d.ts +9 -0
  91. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  92. package/dist/components/TagsInput.vue.d.ts +2 -2
  93. package/dist/components/TimePicker.vue.d.ts +2 -2
  94. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  95. package/dist/components/UnitInput.vue.d.ts +2 -2
  96. package/dist/components/WellPlate.colors.d.ts +9 -0
  97. package/dist/components/WellPlate.conditions.d.ts +26 -0
  98. package/dist/components/WellPlate.geometry.d.ts +23 -0
  99. package/dist/components/WellPlate.interaction.d.ts +71 -0
  100. package/dist/components/WellPlate.legend.d.ts +2 -0
  101. package/dist/components/WellPlate.rendering.d.ts +24 -0
  102. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  103. package/dist/components/WellPlate.vue.d.ts +1 -1
  104. package/dist/components/index.js +2 -2
  105. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  106. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  107. package/dist/{components-DafPc4rM.js → components-Blx4MG--.js} +4073 -4222
  108. package/dist/components-Blx4MG--.js.map +1 -0
  109. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  110. package/dist/composables/autoGroup/classify.d.ts +28 -0
  111. package/dist/composables/autoGroup/colors.d.ts +2 -0
  112. package/dist/composables/autoGroup/columns.d.ts +10 -0
  113. package/dist/composables/autoGroup/compose.d.ts +8 -0
  114. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  115. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  116. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  117. package/dist/composables/autoGroup/index.d.ts +16 -0
  118. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  119. package/dist/composables/autoGroup/template.d.ts +15 -0
  120. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  121. package/dist/composables/autoGroupConstants.d.ts +1 -0
  122. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  123. package/dist/composables/controlComponentBindings.d.ts +1 -1
  124. package/dist/composables/controlSchemaAdapters.d.ts +1 -1
  125. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  126. package/dist/composables/controlSchemaLayout.d.ts +1 -1
  127. package/dist/composables/controlSchemaModel.d.ts +5 -0
  128. package/dist/composables/controlSchemaNormalize.d.ts +1 -1
  129. package/dist/composables/controlSchemaTypes.d.ts +311 -0
  130. package/dist/composables/controlWorkspaceOptions.d.ts +1 -1
  131. package/dist/composables/formBuilderSchema.d.ts +18 -0
  132. package/dist/composables/index.js +3 -3
  133. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  134. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  135. package/dist/composables/useAutoGroup.d.ts +61 -74
  136. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  137. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  138. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  139. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  140. package/dist/composables/useControlSchema.d.ts +4 -316
  141. package/dist/composables/useControlWorkspace.d.ts +1 -1
  142. package/dist/composables/useForm.d.ts +2 -33
  143. package/dist/composables/useFormBuilder.d.ts +2 -9
  144. package/dist/composables/useFormValidation.d.ts +34 -0
  145. package/dist/composables/usePluginClient.d.ts +1 -4
  146. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  147. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  148. package/dist/{composables-BMkPQhVK.js → composables-CHDjDIQT.js} +33 -31
  149. package/dist/composables-CHDjDIQT.js.map +1 -0
  150. package/dist/index.js +4 -4
  151. package/dist/install.js +2 -2
  152. package/dist/styles.css +1432 -660
  153. package/dist/templates/controlSchemaTypes.d.ts +1 -1
  154. package/dist/templates/index.js +1 -1
  155. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  156. package/dist/templates/templateCreateOptions.d.ts +165 -0
  157. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  158. package/dist/templates/types.d.ts +5 -250
  159. package/dist/{templates-bUAWMn5L.js → templates-DSbHJC4v.js} +1536 -297
  160. package/dist/templates-DSbHJC4v.js.map +1 -0
  161. package/dist/types/auto-group.d.ts +79 -9
  162. package/dist/types/componentLabTypes.d.ts +161 -0
  163. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  164. package/dist/types/components.d.ts +14 -311
  165. package/dist/types/form-builder.d.ts +3 -0
  166. package/dist/types/index.d.ts +1 -1
  167. package/dist/{useProtocolTemplates-QZtHFFH2.js → useProtocolTemplates-BbPOYPzO.js} +1220 -454
  168. package/dist/useProtocolTemplates-BbPOYPzO.js.map +1 -0
  169. package/package.json +1 -1
  170. package/src/__tests__/components/AppSidebar.test.ts +67 -0
  171. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  172. package/src/__tests__/components/CollapsibleCard.test.ts +47 -0
  173. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  174. package/src/__tests__/components/FormBuilder.test.ts +57 -0
  175. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  176. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  177. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  178. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +43 -0
  179. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  180. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  181. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  182. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  183. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  184. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  185. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  186. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  187. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  188. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  189. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  190. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  191. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  192. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  193. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  194. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  195. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  196. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  197. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  198. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  199. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  200. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  201. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  202. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  203. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  204. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  205. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  206. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  207. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  208. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  209. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  210. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  211. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  212. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  213. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  214. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  215. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  216. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  217. package/src/components/AppSidebar.story.vue +79 -6
  218. package/src/components/AppSidebar.vue +74 -6
  219. package/src/components/AppTopBar.navigation.ts +62 -0
  220. package/src/components/AppTopBar.vue +17 -44
  221. package/src/components/AutoGroupModal.story.vue +50 -0
  222. package/src/components/AutoGroupModal.vue +441 -158
  223. package/src/components/BaseCheckbox.story.vue +27 -0
  224. package/src/components/BaseCheckbox.vue +63 -1
  225. package/src/components/BaseToggle.story.vue +27 -0
  226. package/src/components/BaseToggle.vue +66 -1
  227. package/src/components/CollapsibleCard.vue +123 -45
  228. package/src/components/ControlWorkspaceView.vue +2 -6
  229. package/src/components/DoseCalculator.vue +13 -73
  230. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  231. package/src/components/ExperimentTimeline.vue +6 -31
  232. package/src/components/FormBuilder.story.vue +13 -0
  233. package/src/components/FormBuilder.vue +2 -7
  234. package/src/components/PlateMapEditor.vue +32 -106
  235. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  236. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  237. package/src/components/PluginWorkspaceView.props.ts +174 -0
  238. package/src/components/PluginWorkspaceView.shell.ts +67 -0
  239. package/src/components/PluginWorkspaceView.vue +88 -404
  240. package/src/components/ProtocolStep.presentation.ts +31 -0
  241. package/src/components/ProtocolStepEditor.state.ts +104 -0
  242. package/src/components/ProtocolStepEditor.vue +48 -179
  243. package/src/components/ProtocolStepParameterField.vue +134 -0
  244. package/src/components/ReagentList.presentation.ts +105 -0
  245. package/src/components/ReagentList.vue +16 -79
  246. package/src/components/SampleSelector.colors.ts +43 -0
  247. package/src/components/SampleSelector.drag.ts +164 -0
  248. package/src/components/SampleSelector.groups.ts +109 -0
  249. package/src/components/SampleSelector.selection.ts +103 -0
  250. package/src/components/SampleSelector.vue +82 -349
  251. package/src/components/SampleSelectorSampleRow.vue +64 -0
  252. package/src/components/ScheduleCalendar.vue +44 -199
  253. package/src/components/SettingsModal.schema.ts +71 -0
  254. package/src/components/SettingsModal.vue +16 -46
  255. package/src/components/WellPlate.colors.ts +56 -0
  256. package/src/components/WellPlate.conditions.ts +100 -0
  257. package/src/components/WellPlate.geometry.ts +91 -0
  258. package/src/components/WellPlate.interaction.ts +272 -0
  259. package/src/components/WellPlate.legend.ts +8 -0
  260. package/src/components/WellPlate.rendering.ts +105 -0
  261. package/src/components/WellPlate.sampleDrop.ts +73 -0
  262. package/src/components/WellPlate.vue +102 -550
  263. package/src/components/internal/FormFieldRendererInternal.vue +23 -5
  264. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  265. package/src/composables/autoGroup/classKey.ts +5 -0
  266. package/src/composables/autoGroup/classify.ts +205 -0
  267. package/src/composables/autoGroup/colors.ts +6 -0
  268. package/src/composables/autoGroup/columns.ts +226 -0
  269. package/src/composables/autoGroup/compose.ts +156 -0
  270. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  271. package/src/composables/autoGroup/csv-shim.ts +44 -0
  272. package/src/composables/autoGroup/fingerprint.ts +49 -0
  273. package/src/composables/autoGroup/index.ts +20 -0
  274. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  275. package/src/composables/autoGroup/template.ts +126 -0
  276. package/src/composables/autoGroup/tokenize.ts +41 -0
  277. package/src/composables/autoGroup/vocab.json +67 -0
  278. package/src/composables/autoGroupConstants.ts +4 -0
  279. package/src/composables/autoGroupGrouping.ts +148 -0
  280. package/src/composables/controlComponentBindings.ts +1 -1
  281. package/src/composables/controlSchemaAdapters.ts +4 -1
  282. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  283. package/src/composables/controlSchemaFormFields.ts +4 -1
  284. package/src/composables/controlSchemaLayout.ts +1 -1
  285. package/src/composables/controlSchemaModel.ts +163 -0
  286. package/src/composables/controlSchemaNormalize.ts +1 -1
  287. package/src/composables/controlSchemaTypes.ts +372 -0
  288. package/src/composables/controlWorkspaceOptions.ts +1 -1
  289. package/src/composables/formBuilderSchema.ts +153 -0
  290. package/src/composables/pluginEndpointBuilder.ts +203 -0
  291. package/src/composables/protocolTemplateCatalog.ts +325 -0
  292. package/src/composables/useAutoGroup.ts +395 -549
  293. package/src/composables/useAutoGroupInputSources.ts +147 -0
  294. package/src/composables/useBioTemplateControls.ts +1 -1
  295. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  296. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  297. package/src/composables/useControlSchema.ts +21 -692
  298. package/src/composables/useControlWorkspace.ts +7 -13
  299. package/src/composables/useForm.ts +5 -187
  300. package/src/composables/useFormBuilder.ts +11 -153
  301. package/src/composables/useFormValidation.ts +154 -0
  302. package/src/composables/usePluginClient.ts +10 -193
  303. package/src/composables/useProtocolTemplates.ts +10 -328
  304. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  305. package/src/styles/components/app-sidebar.css +134 -6
  306. package/src/styles/components/auto-group-modal.css +248 -310
  307. package/src/styles/components/checkbox.css +87 -0
  308. package/src/styles/components/collapsible-card.css +154 -14
  309. package/src/styles/components/toggle.css +80 -0
  310. package/src/templates/controlSchemaTypes.ts +1 -1
  311. package/src/templates/templateAdapterTypes.ts +58 -0
  312. package/src/templates/templateCreateOptions.ts +208 -0
  313. package/src/templates/templateQpcrTypes.ts +48 -0
  314. package/src/templates/types.ts +79 -275
  315. package/src/types/auto-group.ts +107 -9
  316. package/src/types/componentLabTypes.ts +235 -0
  317. package/src/types/componentWorkflowTypes.ts +190 -0
  318. package/src/types/components.ts +95 -424
  319. package/src/types/form-builder.ts +3 -0
  320. package/src/types/index.ts +2 -0
  321. package/dist/components-DafPc4rM.js.map +0 -1
  322. package/dist/composables-BMkPQhVK.js.map +0 -1
  323. package/dist/templates-bUAWMn5L.js.map +0 -1
  324. package/dist/useProtocolTemplates-QZtHFFH2.js.map +0 -1
@@ -0,0 +1,61 @@
1
+ <script setup lang="ts">
2
+ /** Number + unit control used by DoseCalculator volume fields. */
3
+ import type { VolumeUnit, VolumeValue } from '../composables/useDoseCalculator'
4
+
5
+ interface Props {
6
+ label: string
7
+ modelValue: VolumeValue
8
+ units: VolumeUnit[]
9
+ disabled?: boolean
10
+ }
11
+
12
+ const props = withDefaults(defineProps<Props>(), {
13
+ disabled: false,
14
+ })
15
+
16
+ const emit = defineEmits<{
17
+ 'update:modelValue': [value: VolumeValue]
18
+ }>()
19
+
20
+ function handleValueInput(event: Event) {
21
+ const input = event.target as HTMLInputElement
22
+ const value = parseFloat(input.value)
23
+ if (Number.isNaN(value)) return
24
+ emit('update:modelValue', { ...props.modelValue, value })
25
+ }
26
+
27
+ function handleUnitChange(event: Event) {
28
+ const select = event.target as HTMLSelectElement
29
+ emit('update:modelValue', {
30
+ ...props.modelValue,
31
+ unit: select.value as VolumeUnit,
32
+ })
33
+ }
34
+ </script>
35
+
36
+ <template>
37
+ <div class="mint-dose-calculator__field">
38
+ <label class="mint-dose-calculator__field-label">{{ label }}</label>
39
+ <div class="mint-dose-calculator__field-row">
40
+ <input
41
+ type="number"
42
+ :value="modelValue.value"
43
+ :disabled="disabled"
44
+ class="mint-dose-calculator__input"
45
+ min="0"
46
+ step="any"
47
+ @input="handleValueInput"
48
+ />
49
+ <select
50
+ :value="modelValue.unit"
51
+ :disabled="disabled"
52
+ class="mint-dose-calculator__select"
53
+ @change="handleUnitChange"
54
+ >
55
+ <option v-for="unit in units" :key="unit" :value="unit">
56
+ {{ unit }}
57
+ </option>
58
+ </select>
59
+ </div>
60
+ </div>
61
+ </template>
@@ -1,7 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  /** Horizontal or vertical timeline of ordered protocol steps with status indicators, drag-to-reorder, and step-type iconography. */
3
3
  import { ref, computed } from 'vue'
4
- import type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'
4
+ import type { ProtocolStep, ProtocolStepStatus } from '../types'
5
+ import {
6
+ PROTOCOL_STEP_TYPE_COLORS as stepTypeColors,
7
+ PROTOCOL_STEP_TYPE_ICONS as stepTypeIcons,
8
+ formatProtocolDuration as formatDuration,
9
+ } from './ProtocolStep.presentation'
5
10
 
6
11
  interface Props {
7
12
  modelValue?: ProtocolStep[]
@@ -59,28 +64,6 @@ const sortedSteps = computed(() => {
59
64
  return [...props.modelValue].sort((a, b) => a.order - b.order)
60
65
  })
61
66
 
62
- const stepTypeIcons: Record<ProtocolStepType, string> = {
63
- incubation: 'M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z',
64
- wash: 'M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z',
65
- addition: 'M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z',
66
- measurement: 'M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z',
67
- transfer: 'M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4',
68
- centrifuge: 'M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15',
69
- mix: 'M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z',
70
- custom: 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z',
71
- }
72
-
73
- const stepTypeColors: Record<ProtocolStepType, string> = {
74
- incubation: '#F59E0B',
75
- wash: '#06B6D4',
76
- addition: '#10B981',
77
- measurement: '#8B5CF6',
78
- transfer: '#3B82F6',
79
- centrifuge: '#6B7280',
80
- mix: '#F97316',
81
- custom: '#EC4899',
82
- }
83
-
84
67
  const statusClasses: Record<ProtocolStepStatus, string> = {
85
68
  pending: 'mint-timeline__card--pending',
86
69
  in_progress: 'mint-timeline__card--in-progress',
@@ -97,14 +80,6 @@ const iconStatusClasses: Record<ProtocolStepStatus, string> = {
97
80
  skipped: 'mint-timeline__icon--skipped',
98
81
  }
99
82
 
100
- function formatDuration(minutes: number | undefined): string {
101
- if (minutes === undefined) return ''
102
- if (minutes < 60) return `${minutes}m`
103
- const hours = Math.floor(minutes / 60)
104
- const mins = minutes % 60
105
- return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`
106
- }
107
-
108
83
  function getStepColor(step: ProtocolStep): string {
109
84
  return props.colorByType && !props.colorByStatus ? stepTypeColors[step.type] : ''
110
85
  }
@@ -5,6 +5,11 @@ import { defineControlModel, defineControls } from '../composables/useControlSch
5
5
 
6
6
  type FormSize = 'sm' | 'md' | 'lg'
7
7
 
8
+ const icons = {
9
+ scale: ['M16 16l3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1z', 'M2 16l3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1z', 'M7 21h10', 'M12 3v18', 'M3 7h2c2 0 5-1 7-4 2 3 5 4 7 4h2'],
10
+ eye: ['M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z', 'M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'],
11
+ }
12
+
8
13
  const analysisModel = defineControlModel({
9
14
  views: {
10
15
  analysis: {
@@ -32,6 +37,10 @@ const analysisModel = defineControlModel({
32
37
  label: 'Normalize intensities',
33
38
  default: true,
34
39
  type: 'toggle',
40
+ hint: 'Scale each sample before fitting',
41
+ icon: icons.scale,
42
+ iconColor: '#6366f1',
43
+ iconBg: '#e0e7ff',
35
44
  },
36
45
  },
37
46
  },
@@ -50,6 +59,10 @@ const analysisModel = defineControlModel({
50
59
  label: 'Exclude outliers',
51
60
  default: true,
52
61
  type: 'checkbox',
62
+ hint: 'Hide flagged injections from summaries',
63
+ icon: icons.eye,
64
+ iconColor: '#0ea5e9',
65
+ iconBg: '#e0f2fe',
53
66
  },
54
67
  },
55
68
  },
@@ -27,9 +27,9 @@ import type { FormSchema, FormEnhancements, UseFormBuilderReturn } from '../type
27
27
  import type { WizardStep } from '../types'
28
28
  import {
29
29
  controlsToFormSchema,
30
- defineControlModel,
31
30
  getControlDefaults,
32
31
  mergeControlWorkspaceOptions,
32
+ resolveControlModel,
33
33
  type ControlModel,
34
34
  type ControlModelBinding,
35
35
  type ControlSchema,
@@ -80,8 +80,7 @@ const emit = defineEmits<{
80
80
  }>()
81
81
 
82
82
  const resolvedModel = computed<ControlModelBinding | undefined>(() => {
83
- if (props.model === undefined) return undefined
84
- return isControlModelBinding(props.model) ? props.model : defineControlModel(props.model)
83
+ return resolveControlModel(props.model)
85
84
  })
86
85
 
87
86
  const resolvedControls = computed<ControlSchema | undefined>(() =>
@@ -197,10 +196,6 @@ function builderFieldNames(): string[] {
197
196
  return builder.fields.map(field => field.name)
198
197
  }
199
198
 
200
- function isControlModelBinding(model: ControlModel | ControlModelBinding): model is ControlModelBinding {
201
- return 'controls' in model && 'controlOptions' in model
202
- }
203
-
204
199
  defineExpose({
205
200
  form: builder.form,
206
201
  validate: builder.validate,
@@ -1,11 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  /** Full plate-map design environment for 96/384-well plates with sample assignment, slot-color coding, undo/redo, and CSV/JSON import-export. */
3
3
  import { ref, computed, watch } from 'vue'
4
- import type { PlateMapEditorState, WellPlateFormat, SampleType, Well } from '../types'
4
+ import type { PlateMapEditorState, WellPlateFormat, SampleType, Well, PlateMap } from '../types'
5
5
  import { useWellPlateEditor } from '../composables/useWellPlateEditor'
6
6
  import { useEventListener } from '../composables/useEventListener'
7
7
  import WellPlate from './WellPlate.vue'
8
8
  import SampleLegend from './SampleLegend.vue'
9
+ import PlateMapEditorToolbarInternal from './internal/PlateMapEditorToolbarInternal.vue'
9
10
 
10
11
  // Slot colors matching MSExpDesigner
11
12
  type SlotPosition = 'R' | 'G' | 'B' | 'Y'
@@ -73,6 +74,10 @@ function getPlateSlot(plateId: string, plateIndex: number): SlotPosition {
73
74
  return plateSlots.value.get(plateId)!
74
75
  }
75
76
 
77
+ function getPlateSlotColor(plateId: string, plateIndex: number): string {
78
+ return SLOT_COLORS[getPlateSlot(plateId, plateIndex)]
79
+ }
80
+
76
81
  const sampleColors = computed(() => {
77
82
  const colors: Record<string, string> = {}
78
83
  for (const sample of editor.samples.value) {
@@ -98,13 +103,18 @@ const wellsData = computed(() => {
98
103
  return wells
99
104
  })
100
105
 
101
- // Count samples in a plate
102
- function getPlateWellCount(plateId: string): number {
103
- const plate = editor.plates.value.find(p => p.id === plateId)
104
- if (!plate) return 0
106
+ function countPlateAssignedWells(plate: PlateMap): number {
105
107
  return Object.values(plate.wells).filter(w => w.sampleType).length
106
108
  }
107
109
 
110
+ const plateWellCounts = computed<Record<string, number>>(() => {
111
+ const counts: Record<string, number> = {}
112
+ for (const plate of editor.plates.value) {
113
+ counts[plate.id] = countPlateAssignedWells(plate)
114
+ }
115
+ return counts
116
+ })
117
+
108
118
  watch(
109
119
  () => editor.state.value,
110
120
  (newState) => emit('update:modelValue', { ...newState }),
@@ -230,107 +240,23 @@ useEventListener(() => document, 'keydown', handleKeyDown)
230
240
  <!-- Main plate area -->
231
241
  <div class="mint-plate-editor__main">
232
242
  <!-- Toolbar -->
233
- <div v-if="showToolbar" class="mint-plate-editor__toolbar">
234
- <!-- Plate tabs -->
235
- <div class="mint-plate-editor__tabs">
236
- <button
237
- v-for="(plate, index) in editor.plates.value"
238
- :key="plate.id"
239
- type="button"
240
- :class="['mint-plate-editor__tab', { 'mint-plate-editor__tab--active': plate.id === editor.activePlate.value?.id }]"
241
- @click="editor.setActivePlate(plate.id)"
242
- >
243
- <span
244
- class="mint-plate-editor__tab-slot"
245
- :style="{ backgroundColor: SLOT_COLORS[getPlateSlot(plate.id, index)] }"
246
- />
247
- <span class="mint-plate-editor__tab-name">{{ plate.name }}</span>
248
- <span
249
- v-if="getPlateWellCount(plate.id) > 0"
250
- class="mint-plate-editor__tab-count"
251
- >
252
- {{ getPlateWellCount(plate.id) }}
253
- </span>
254
- <button
255
- v-if="editor.plates.value.length > 1"
256
- type="button"
257
- class="mint-plate-editor__tab-remove"
258
- :aria-label="`Remove ${plate.name}`"
259
- @click.stop="handleRemovePlate(plate.id)"
260
- >
261
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
262
- <path d="M18 6 6 18" /><path d="m6 6 12 12" />
263
- </svg>
264
- </button>
265
- </button>
266
-
267
- <button
268
- v-if="allowAddPlates && editor.plates.value.length < maxPlates"
269
- type="button"
270
- class="mint-plate-editor__add-plate"
271
- aria-label="Add plate"
272
- @click="handleAddPlate"
273
- >
274
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
275
- <path d="M5 12h14" /><path d="M12 5v14" />
276
- </svg>
277
- <span>Add</span>
278
- </button>
279
- </div>
280
-
281
- <div class="mint-plate-editor__spacer" />
282
-
283
- <!-- Actions -->
284
- <div class="mint-plate-editor__actions">
285
- <button
286
- type="button"
287
- :disabled="!editor.canUndo.value"
288
- class="mint-plate-editor__action-btn"
289
- title="Undo (Ctrl+Z)"
290
- @click="handleUndo"
291
- >
292
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
293
- <path d="M9 14 4 9l5-5" /><path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" />
294
- </svg>
295
- </button>
296
-
297
- <button
298
- type="button"
299
- :disabled="!editor.canRedo.value"
300
- class="mint-plate-editor__action-btn"
301
- title="Redo (Ctrl+Shift+Z)"
302
- @click="handleRedo"
303
- >
304
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
305
- <path d="m15 14 5-5-5-5" /><path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13" />
306
- </svg>
307
- </button>
308
-
309
- <div class="mint-plate-editor__divider" />
310
-
311
- <button
312
- type="button"
313
- class="mint-plate-editor__action-btn"
314
- title="Import"
315
- @click="showImportModal = true"
316
- >
317
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
318
- <path d="M12 3v12" /><path d="m17 8-5-5-5 5" /><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
319
- </svg>
320
- </button>
321
-
322
- <button
323
- type="button"
324
- class="mint-plate-editor__action-btn"
325
- title="Export JSON"
326
- @click="handleExport('json')"
327
- >
328
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
329
- <path d="M12 15V3" /><path d="m7 10 5 5 5-5" /><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
330
- </svg>
331
- </button>
332
- </div>
333
- </div>
243
+ <PlateMapEditorToolbarInternal
244
+ v-if="showToolbar"
245
+ :plates="editor.plates.value"
246
+ :active-plate-id="editor.activePlate.value?.id"
247
+ :plate-well-counts="plateWellCounts"
248
+ :can-add-plate="allowAddPlates && editor.plates.value.length < maxPlates"
249
+ :can-undo="editor.canUndo.value"
250
+ :can-redo="editor.canRedo.value"
251
+ :slot-color-for-plate="getPlateSlotColor"
252
+ @select-plate="editor.setActivePlate"
253
+ @remove-plate="handleRemovePlate"
254
+ @add-plate="handleAddPlate"
255
+ @undo="handleUndo"
256
+ @redo="handleRedo"
257
+ @import="showImportModal = true"
258
+ @export-json="handleExport('json')"
259
+ />
334
260
 
335
261
  <!-- Well plate -->
336
262
  <WellPlate
@@ -0,0 +1,182 @@
1
+ import { computed, reactive, watch } from 'vue'
2
+ import type { ComputedRef } from 'vue'
3
+ import type { PillNavItem } from '../types'
4
+ import type {
5
+ ControlComponentBinding,
6
+ ControlComponentBindingsById,
7
+ ControlComponentBindingsConfig,
8
+ ControlComponentPropsByIdMap,
9
+ ControlComponentPropsMap,
10
+ ControlModel,
11
+ ControlModelBinding,
12
+ ControlSchema,
13
+ ControlWorkspaceOptions,
14
+ } from '../composables/useControlSchema'
15
+ import {
16
+ controlValuesToComponentBindings,
17
+ controlValuesToComponentBindingsById,
18
+ controlValuesToComponentProps,
19
+ controlsToViewItems,
20
+ getControlDefaults,
21
+ getDefaultControlView,
22
+ mergeControlWorkspaceOptions,
23
+ resolveControlModel,
24
+ } from '../composables/useControlSchema'
25
+
26
+ export interface PluginWorkspaceControlsOptions {
27
+ model: () => ControlModel | ControlModelBinding | undefined
28
+ controls: () => ControlSchema | undefined
29
+ controlOptions: () => ControlWorkspaceOptions
30
+ modelValue: () => Record<string, unknown> | undefined
31
+ values: () => Record<string, unknown> | undefined
32
+ componentBindings: () => ControlComponentBindingsConfig | undefined
33
+ componentProps: () => ControlComponentPropsMap | undefined
34
+ componentPropsById: () => ControlComponentPropsByIdMap | undefined
35
+ emitValues: (values: Record<string, unknown>) => void
36
+ }
37
+
38
+ export interface PluginWorkspaceControls {
39
+ resolvedModel: ComputedRef<ControlModelBinding | undefined>
40
+ resolvedControls: ComputedRef<ControlSchema | undefined>
41
+ resolvedControlOptions: ComputedRef<ControlWorkspaceOptions>
42
+ generatedPillNav: ComputedRef<PillNavItem[]>
43
+ generatedDefaultView: ComputedRef<string>
44
+ internalControlValues: Record<string, unknown>
45
+ resolvedComponentBindings: ComputedRef<ControlComponentBinding[]>
46
+ resolvedComponentBindingsById: ComputedRef<ControlComponentBindingsById>
47
+ resolvedComponentProps: ComputedRef<Record<string, unknown>>
48
+ resolvedComponentPropsById: ComputedRef<Record<string, Record<string, unknown>>>
49
+ handleControlValuesUpdate: (values: Record<string, unknown>) => void
50
+ }
51
+
52
+ export function usePluginWorkspaceControls(
53
+ options: PluginWorkspaceControlsOptions,
54
+ ): PluginWorkspaceControls {
55
+ const resolvedModel = computed<ControlModelBinding | undefined>(() =>
56
+ resolveControlModel(options.model()),
57
+ )
58
+
59
+ const resolvedControls = computed<ControlSchema | undefined>(() =>
60
+ options.controls() ?? resolvedModel.value?.controls,
61
+ )
62
+
63
+ const resolvedControlOptions = computed<ControlWorkspaceOptions>(() =>
64
+ mergeControlWorkspaceOptions(resolvedModel.value?.controlOptions ?? {}, options.controlOptions()),
65
+ )
66
+
67
+ const externalControlValues = computed(() => options.modelValue() ?? options.values())
68
+ const internalControlValues = reactive<Record<string, unknown>>({})
69
+ let syncingControlValues = false
70
+
71
+ const generatedControlDefaults = computed<Record<string, unknown>>(() => {
72
+ if (!resolvedControls.value) return {}
73
+ return {
74
+ ...getControlDefaults(resolvedControls.value),
75
+ ...(resolvedControlOptions.value.initialValues ?? {}),
76
+ }
77
+ })
78
+
79
+ function replaceControlValues(values: Record<string, unknown>) {
80
+ for (const key of Object.keys(internalControlValues)) {
81
+ if (!(key in values)) {
82
+ delete internalControlValues[key]
83
+ }
84
+ }
85
+ Object.assign(internalControlValues, values)
86
+ }
87
+
88
+ function emitControlValues() {
89
+ options.emitValues({ ...internalControlValues })
90
+ }
91
+
92
+ function syncResolvedControlValues() {
93
+ syncingControlValues = true
94
+ replaceControlValues({
95
+ ...generatedControlDefaults.value,
96
+ ...(externalControlValues.value === undefined ? internalControlValues : externalControlValues.value),
97
+ })
98
+ syncingControlValues = false
99
+ }
100
+
101
+ function handleControlValuesUpdate(values: Record<string, unknown>) {
102
+ syncingControlValues = true
103
+ replaceControlValues({
104
+ ...generatedControlDefaults.value,
105
+ ...values,
106
+ })
107
+ syncingControlValues = false
108
+ emitControlValues()
109
+ }
110
+
111
+ const resolvedComponentBindings = computed(() =>
112
+ controlValuesToComponentBindings(
113
+ internalControlValues,
114
+ options.componentBindings() ?? resolvedModel.value?.componentBindings,
115
+ ),
116
+ )
117
+
118
+ const resolvedComponentBindingsById = computed(() =>
119
+ controlValuesToComponentBindingsById(
120
+ internalControlValues,
121
+ options.componentBindings() ?? resolvedModel.value?.componentBindings,
122
+ ),
123
+ )
124
+
125
+ const resolvedComponentProps = computed(() => {
126
+ const mapping = options.componentProps() ?? resolvedModel.value?.componentProps
127
+ return mapping === undefined ? {} : controlValuesToComponentProps(internalControlValues, mapping)
128
+ })
129
+
130
+ const resolvedComponentPropsById = computed(() => {
131
+ const mappings = options.componentPropsById() ?? resolvedModel.value?.componentPropsById
132
+ if (mappings === undefined) return {}
133
+
134
+ return Object.fromEntries(
135
+ Object.entries(mappings).map(([id, mapping]) => [
136
+ id,
137
+ controlValuesToComponentProps(internalControlValues, mapping),
138
+ ]),
139
+ )
140
+ })
141
+
142
+ const generatedPillNav = computed<PillNavItem[]>(() => {
143
+ if (!resolvedControls.value) return []
144
+ return controlsToViewItems(resolvedControls.value, resolvedControlOptions.value)
145
+ })
146
+
147
+ const generatedDefaultView = computed(() => {
148
+ if (!resolvedControls.value) return ''
149
+ return getDefaultControlView(resolvedControls.value, resolvedControlOptions.value)
150
+ })
151
+
152
+ syncResolvedControlValues()
153
+
154
+ watch(
155
+ [generatedControlDefaults, externalControlValues],
156
+ syncResolvedControlValues,
157
+ { deep: true },
158
+ )
159
+
160
+ watch(
161
+ internalControlValues,
162
+ () => {
163
+ if (syncingControlValues) return
164
+ emitControlValues()
165
+ },
166
+ { deep: true, flush: 'sync' },
167
+ )
168
+
169
+ return {
170
+ resolvedModel,
171
+ resolvedControls,
172
+ resolvedControlOptions,
173
+ generatedPillNav,
174
+ generatedDefaultView,
175
+ internalControlValues,
176
+ resolvedComponentBindings,
177
+ resolvedComponentBindingsById,
178
+ resolvedComponentProps,
179
+ resolvedComponentPropsById,
180
+ handleControlValuesUpdate,
181
+ }
182
+ }
@@ -0,0 +1,106 @@
1
+ import { computed, ref, type ComputedRef, type Ref, type WritableComputedRef } from 'vue'
2
+ import type {
3
+ PageSelectorItem,
4
+ PageSelectorItemInput,
5
+ PillNavItem,
6
+ PillNavItemInput,
7
+ } from '../types'
8
+
9
+ type ReadableRef<T> = Readonly<Ref<T>>
10
+
11
+ export interface PluginWorkspaceNavigationOptions {
12
+ activeView: () => string | undefined
13
+ defaultActiveView: () => string | undefined
14
+ currentPillId: () => string | undefined
15
+ currentPageSelectorId: () => string | undefined
16
+ pillNav: () => PillNavItemInput[] | undefined
17
+ pageSelector: () => PageSelectorItemInput[] | undefined
18
+ panelIds: () => string[]
19
+ generatedPillNav: ReadableRef<readonly PillNavItem[]>
20
+ generatedDefaultView: ReadableRef<string>
21
+ emitActiveView: (viewId: string) => void
22
+ emitPageSelectorSelect: (page: PageSelectorItem) => void
23
+ emitPillSelect: (item: PillNavItem) => void
24
+ }
25
+
26
+ export interface PluginWorkspaceNavigation {
27
+ resolvedPillNav: ComputedRef<PillNavItemInput[] | undefined>
28
+ firstConfiguredViewId: ComputedRef<string>
29
+ resolvedActiveView: WritableComputedRef<string>
30
+ resolvedCurrentPillId: ComputedRef<string>
31
+ resolvedCurrentPageSelectorId: ComputedRef<string>
32
+ setActiveView: (viewId: string) => void
33
+ handlePageSelectorSelect: (page: PageSelectorItem) => void
34
+ handlePillSelect: (item: PillNavItem) => void
35
+ }
36
+
37
+ export function usePluginWorkspaceNavigation(
38
+ options: PluginWorkspaceNavigationOptions,
39
+ ): PluginWorkspaceNavigation {
40
+ const internalActiveView = ref(options.defaultActiveView())
41
+
42
+ const resolvedPillNav = computed<PillNavItemInput[] | undefined>(() => {
43
+ if (options.pillNav() !== undefined) return options.pillNav()
44
+ return options.generatedPillNav.value.length > 0
45
+ ? [...options.generatedPillNav.value]
46
+ : undefined
47
+ })
48
+
49
+ const firstConfiguredViewId = computed(() =>
50
+ options.defaultActiveView()
51
+ ?? firstItemId(options.pillNav())
52
+ ?? options.generatedDefaultView.value
53
+ ?? firstItemId(options.pageSelector())
54
+ ?? options.panelIds()[0]
55
+ ?? '',
56
+ )
57
+
58
+ const resolvedActiveView = computed({
59
+ get: () =>
60
+ options.activeView()
61
+ ?? options.currentPillId()
62
+ ?? options.currentPageSelectorId()
63
+ ?? internalActiveView.value
64
+ ?? firstConfiguredViewId.value,
65
+ set: (value: string) => {
66
+ internalActiveView.value = value
67
+ options.emitActiveView(value)
68
+ },
69
+ })
70
+
71
+ const resolvedCurrentPillId = computed(() => options.currentPillId() ?? resolvedActiveView.value)
72
+ const resolvedCurrentPageSelectorId = computed(() =>
73
+ options.currentPageSelectorId() ?? resolvedActiveView.value,
74
+ )
75
+
76
+ function setActiveView(viewId: string) {
77
+ resolvedActiveView.value = viewId
78
+ }
79
+
80
+ function handlePageSelectorSelect(page: PageSelectorItem) {
81
+ setActiveView(page.id)
82
+ options.emitPageSelectorSelect(page)
83
+ }
84
+
85
+ function handlePillSelect(item: PillNavItem) {
86
+ setActiveView(item.id)
87
+ options.emitPillSelect(item)
88
+ }
89
+
90
+ return {
91
+ resolvedPillNav,
92
+ firstConfiguredViewId,
93
+ resolvedActiveView,
94
+ resolvedCurrentPillId,
95
+ resolvedCurrentPageSelectorId,
96
+ setActiveView,
97
+ handlePageSelectorSelect,
98
+ handlePillSelect,
99
+ }
100
+ }
101
+
102
+ function firstItemId(items?: readonly (string | { id: string })[]): string | undefined {
103
+ const item = items?.[0]
104
+ if (item === undefined) return undefined
105
+ return typeof item === 'string' ? item : item.id
106
+ }