@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
@@ -1,374 +1,68 @@
1
- import { computed, reactive, ref, watch, type ComputedRef, type Ref } from 'vue'
1
+ import {
2
+ defaultValueForControl,
3
+ normalizeControls,
4
+ } from './controlSchemaNormalize'
5
+ import {
6
+ controlToFormField,
7
+ } from './controlSchemaFormFields'
8
+ import {
9
+ controlsToFormSchema,
10
+ controlsToSectionFormSchema,
11
+ controlsToSectionFormSchemas,
12
+ controlsToSettingsSchema,
13
+ controlsToSidebarPanels,
14
+ controlsToTopBarSettingsConfig,
15
+ controlsToViewItems,
16
+ } from './controlSchemaAdapters'
2
17
  import type {
3
- PillNavItem,
4
- SidebarToolSection,
5
- SelectOption,
6
- SettingsModalSchema,
7
- TopBarSettingsConfig,
8
- } from '../types'
9
- import type { AccessPolicy, AccessAudienceInput } from '../permissions'
10
- import type {
11
- FieldCondition,
12
- FieldValidation,
13
- FormFieldSchema,
14
- FormFieldType,
15
- FormSchema,
16
- FormSectionSchema,
17
- } from '../types/form-builder'
18
- import { getTypeDefault } from './formBuilderRegistry'
19
- import type { WellConcentration } from './useDoseCalculator'
20
-
21
- export type ControlOptionValue = string | number | boolean
22
- export type ControlOption = ControlOptionValue | SelectOption<unknown>
23
- export type ControlPrimitive = string | number | boolean
24
- export type ControlShorthand = ControlPrimitive | readonly ControlOption[]
25
- export type ControlInput = ControlDefinition | ControlShorthand
26
-
27
- export interface ControlSectionConfig {
28
- id?: string
29
- label?: string
30
- title?: string
31
- description?: string
32
- subtitle?: string
33
- icon?: string | string[]
34
- iconColor?: string
35
- iconBg?: string
36
- columns?: 1 | 2 | 3
37
- condition?: FieldCondition
38
- access?: AccessPolicy
39
- visibleFor?: AccessAudienceInput
40
- requiresAdmin?: boolean
41
- permissions?: readonly string[]
42
- anyPermissions?: readonly string[]
43
- defaultOpen?: boolean
44
- showToggle?: boolean
45
- }
46
-
47
- export interface ControlViewConfig {
48
- label?: string
49
- icon?: string
50
- to?: string
51
- href?: string
52
- disabled?: boolean
53
- children?: PillNavItem['children']
54
- }
55
-
56
- export interface ControlSidebarConfig extends Omit<ControlSectionConfig, 'id' | 'title' | 'description' | 'columns'> {
57
- enabled?: boolean
58
- }
59
-
60
- export interface ControlDefinition {
61
- type?: FormFieldType
62
- label?: string
63
- default?: unknown
64
- defaultValue?: unknown
65
- placeholder?: string
66
- hint?: string
67
- size?: 'sm' | 'md' | 'lg'
68
- disabled?: boolean
69
- readonly?: boolean
70
- required?: boolean | string
71
- min?: number | { value: number; message: string }
72
- max?: number | { value: number; message: string }
73
- minLength?: number | { value: number; message: string }
74
- maxLength?: number | { value: number; message: string }
75
- email?: boolean | string
76
- pattern?: string | { value: string; message: string }
77
- validation?: FieldValidation
78
- condition?: FieldCondition
79
- access?: AccessPolicy
80
- visibleFor?: AccessAudienceInput
81
- requiresAdmin?: boolean
82
- permissions?: readonly string[]
83
- anyPermissions?: readonly string[]
84
- options?: readonly ControlOption[]
85
- section?: string
86
- sectionLabel?: string
87
- sectionDescription?: string
88
- sectionSubtitle?: string
89
- view?: string
90
- order?: number
91
- colSpan?: number
92
- props?: Record<string, unknown>
93
- sidebar?: boolean | ControlSidebarConfig
94
- }
95
-
96
- export type ControlSchema = Record<string, ControlInput>
97
- export type ControlFormSchema = Extract<FormSchema, { sections: FormSectionSchema[] }>
98
-
99
- export interface ControlSchemaOptions {
100
- view?: string
101
- views?: Record<string, ControlViewConfig>
102
- section?: string
103
- sectionLabel?: string
104
- sections?: Record<string, ControlSectionConfig>
105
- columns?: 1 | 2 | 3
106
- submitLabel?: string
107
- cancelLabel?: string
108
- showCancel?: boolean
109
- }
110
-
111
- export interface ControlWorkspaceOptions extends ControlSchemaOptions {
112
- initialValues?: Record<string, unknown>
113
- topBarSettings?: Omit<TopBarSettingsConfig, 'schema' | 'controls' | 'controlOptions' | 'values'>
114
- }
115
-
116
- export interface ControlModelSectionConfig extends ControlSectionConfig {
117
- controls: ControlSchema
118
- sidebar?: boolean | ControlSidebarConfig
119
- }
120
-
121
- export interface ControlModelViewConfig extends ControlViewConfig {
122
- controls?: ControlSchema
123
- section?: string
124
- sectionLabel?: string
125
- sectionDescription?: string
126
- sections?: Record<string, ControlModelSectionConfig>
127
- }
128
-
129
- export interface ControlModel extends Omit<ControlWorkspaceOptions, 'sections' | 'views'> {
130
- controls?: ControlSchema
131
- sections?: Record<string, ControlModelSectionConfig>
132
- views?: Record<string, ControlModelViewConfig>
133
- /** Optional SDK component bindings returned with generated component props for custom workspace slots. */
134
- componentBindings?: ControlComponentBindingsConfig
135
- /** Alias for componentBindings in raw control models. */
136
- components?: ControlComponentBindingsConfig
137
- /** Optional ControlWorkspaceView componentProps mapping returned with the generated controls/options. */
138
- componentProps?: ControlComponentPropsMap
139
- /** Optional named componentProps mappings returned for multiple SDK components. */
140
- componentPropsById?: ControlComponentPropsByIdMap
141
- }
142
-
143
- export interface ControlModelBinding {
144
- controls: ControlSchema
145
- controlOptions: ControlWorkspaceOptions
146
- componentBindings?: ControlComponentBindingsConfig
147
- componentProps?: ControlComponentPropsMap
148
- componentPropsById?: ControlComponentPropsByIdMap
149
- }
150
-
151
- export interface ControlSidebarBinding {
152
- panels: Record<string, SidebarToolSection[]>
153
- forms: Record<string, ControlFormSchema>
154
- viewIds: string[]
155
- viewItems: PillNavItem[]
156
- defaultView: string
157
- }
158
-
159
- export interface ControlFormBinding {
160
- schema: ControlFormSchema
161
- }
162
-
163
- export interface ControlSettingsBinding {
164
- schema: SettingsModalSchema
165
- }
166
-
167
- export interface ControlTopBarSettingsBinding {
168
- showSettings: true
169
- settingsConfig: TopBarSettingsConfig
170
- }
171
-
172
- export interface ControlWorkspaceFormBinding extends ControlFormBinding {
173
- modelValue: Record<string, unknown>
174
- 'onUpdate:modelValue': (values: Record<string, unknown>) => void
175
- }
176
-
177
- export interface ControlWorkspaceSidebarBinding extends ControlSidebarBinding {
178
- activeView: string
179
- modelValue: Record<string, unknown>
180
- 'onUpdate:modelValue': (values: Record<string, unknown>) => void
181
- values: Record<string, unknown>
182
- 'onUpdate:values': (values: Record<string, unknown>) => void
183
- }
184
-
185
- export interface ControlWorkspaceTopBarSettingsBinding extends ControlTopBarSettingsBinding {
186
- onSettingsValuesChange: (values: Record<string, unknown>) => void
187
- }
188
-
189
- export interface ControlWorkspacePillNavBinding {
190
- items: PillNavItem[]
191
- currentItemId: string
192
- onSelect: (item: PillNavItem) => void
193
- }
194
-
195
- export interface ControlWorkspaceTopBarBinding extends ControlWorkspaceTopBarSettingsBinding {
196
- pillNav: PillNavItem[]
197
- currentPillId: string
198
- onPillSelect: (item: PillNavItem) => void
199
- }
200
-
201
- export type ControlWorkspaceAppTopBarPillBinding = ControlWorkspaceTopBarBinding
202
-
203
- export interface ControlWorkspaceComponentBindings {
204
- form: ControlWorkspaceFormBinding
205
- sidebar: ControlWorkspaceSidebarBinding
206
- topBar: ComputedRef<ControlWorkspaceTopBarBinding>
207
- topBarSettings: ControlWorkspaceTopBarSettingsBinding
208
- pillNav: ControlWorkspacePillNavBinding
209
- componentBindings: ComputedRef<ControlComponentBinding[]>
210
- componentBindingsById: ComputedRef<ControlComponentBindingsById>
211
- componentProps: ComputedRef<Record<string, unknown>>
212
- componentPropsById: ComputedRef<Record<string, Record<string, unknown>>>
213
- }
214
-
215
- export type ControlComponentPropSource<TValues extends Record<string, unknown> = Record<string, unknown>> =
216
- | (keyof TValues & string)
217
- | ((values: TValues) => unknown)
218
-
219
- export type ControlComponentPropsMap<TValues extends Record<string, unknown> = Record<string, unknown>> =
220
- | readonly (keyof TValues & string)[]
221
- | Record<string, ControlComponentPropSource<TValues>>
222
-
223
- export type ControlComponentPropsByIdMap<TValues extends Record<string, unknown> = Record<string, unknown>> =
224
- Record<string, ControlComponentPropsMap<TValues>>
225
-
226
- export interface ControlComponentBindingConfig<TValues extends Record<string, unknown> = Record<string, unknown>> {
227
- id?: string
228
- component: string
229
- props?: ControlComponentPropsMap<TValues>
230
- }
231
-
232
- export interface ControlComponentBindingRecordConfig<TValues extends Record<string, unknown> = Record<string, unknown>> {
233
- component: string
234
- props?: ControlComponentPropsMap<TValues>
235
- }
236
-
237
- export type ControlComponentBindingsConfig<TValues extends Record<string, unknown> = Record<string, unknown>> =
238
- | readonly ControlComponentBindingConfig<TValues>[]
239
- | Record<string, ControlComponentBindingRecordConfig<TValues>>
240
-
241
- export interface ControlComponentBinding {
242
- id: string
243
- component: string
244
- props: Record<string, unknown>
245
- }
246
-
247
- export type ControlComponentBindingsById = Record<string, ControlComponentBinding>
248
-
249
- export interface WellPlateControlPropsOptions<TValues extends Record<string, unknown> = Record<string, unknown>> {
250
- selectedWells?: ControlComponentPropSource<TValues>
251
- format?: ControlComponentPropSource<TValues>
252
- wells?: ControlComponentPropSource<TValues>
253
- disabled?: ControlComponentPropSource<TValues>
254
- readonly?: ControlComponentPropSource<TValues>
255
- showLegend?: ControlComponentPropSource<TValues>
256
- showSampleTypeIndicator?: ControlComponentPropSource<TValues>
257
- /** Listener for WellPlate v-model updates. Set false to keep generated props one-way. */
258
- onUpdateModelValue?: ((values: TValues) => (wellIds: string[]) => void) | false
259
- }
260
-
261
- export interface DoseCalculatorControlPropsOptions<TValues extends Record<string, unknown> = Record<string, unknown>> {
262
- mode?: ControlComponentPropSource<TValues>
263
- targetWells?: ControlComponentPropSource<TValues>
264
- /** Control value key used by the default apply-to-wells handler. */
265
- wells?: ControlComponentPropSource<TValues>
266
- disabled?: ControlComponentPropSource<TValues>
267
- molecularWeight?: ControlComponentPropSource<TValues>
268
- /** Listener for DoseCalculator apply-to-wells. Set false to keep generated props one-way. */
269
- onApplyToWells?: ((values: TValues) => (results: WellConcentration[]) => void) | false
270
- }
271
-
272
- export interface WellPlateDoseControlPropsOptions<TValues extends Record<string, unknown> = Record<string, unknown>> {
273
- plateId?: string
274
- doseId?: string
275
- plate?: WellPlateControlPropsOptions<TValues>
276
- dose?: DoseCalculatorControlPropsOptions<TValues>
277
- }
278
-
279
- export interface DoseDesignControlModelOptions {
280
- viewId?: string
281
- viewLabel?: string
282
- sectionId?: string
283
- sectionLabel?: string
284
- sectionDescription?: string
285
- selectedWells?: readonly string[]
286
- plateFormat?: number
287
- plateFormats?: readonly number[]
288
- doseMode?: 'serial' | 'dilution' | 'conversion'
289
- doseModes?: readonly ('serial' | 'dilution' | 'conversion')[]
290
- disabled?: boolean
291
- includeMolecularWeight?: boolean
292
- molecularWeight?: number
293
- componentProps?: WellPlateDoseControlPropsOptions
294
- }
295
-
296
- export interface UseControlSchemaReturn<TControls extends ControlSchema> {
297
- controls: TControls
298
- fields: FormFieldSchema[]
299
- formSchema: ControlFormSchema
300
- form: ControlFormBinding
301
- settingsSchema: SettingsModalSchema
302
- settings: ControlSettingsBinding
303
- topBarSettingsConfig: TopBarSettingsConfig
304
- topBarSettings: ControlTopBarSettingsBinding
305
- sidebarPanels: Record<string, SidebarToolSection[]>
306
- viewIds: string[]
307
- viewItems: PillNavItem[]
308
- defaultView: string
309
- sectionSchemas: Record<string, ControlFormSchema>
310
- sidebar: ControlSidebarBinding
311
- initialValues: ControlValues<TControls>
312
- sectionSchema: (sectionId: string) => ControlFormSchema
313
- }
314
-
315
- export interface UseControlWorkspaceReturn<TControls extends ControlSchema>
316
- extends Omit<UseControlSchemaReturn<TControls>, 'form' | 'sidebar' | 'topBarSettings'> {
317
- schema: UseControlSchemaReturn<TControls>
318
- values: ControlValues<TControls> & Record<string, unknown>
319
- activeView: Ref<string>
320
- form: ControlWorkspaceFormBinding
321
- sidebar: ControlWorkspaceSidebarBinding
322
- topBar: ComputedRef<ControlWorkspaceTopBarBinding>
323
- pillNav: ControlWorkspacePillNavBinding
324
- topBarSettings: ControlWorkspaceTopBarSettingsBinding
325
- bindings: ControlWorkspaceComponentBindings
326
- componentBindings: ComputedRef<ControlComponentBinding[]>
327
- componentBindingsById: ComputedRef<ControlComponentBindingsById>
328
- componentProps: ComputedRef<Record<string, unknown>>
329
- componentPropsById: ComputedRef<Record<string, Record<string, unknown>>>
330
- setActiveView: (viewId: string) => void
331
- setValues: (values: Record<string, unknown>) => void
332
- resetValues: (values?: Record<string, unknown>) => void
333
- getComponentProps: (
334
- mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>
335
- ) => Record<string, unknown>
336
- getComponentPropsById: (
337
- mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>
338
- ) => Record<string, Record<string, unknown>>
339
- getComponentBindings: (
340
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>
341
- ) => ControlComponentBinding[]
342
- getComponentBindingsById: (
343
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>
344
- ) => ControlComponentBindingsById
345
- }
346
-
347
- export type ControlValues<TControls extends ControlSchema> = {
348
- [K in keyof TControls]: ControlValue<TControls[K]>
349
- }
350
-
351
- type ControlValue<TControl> =
352
- TControl extends { default: infer TDefault }
353
- ? TDefault
354
- : TControl extends { defaultValue: infer TDefaultValue }
355
- ? TDefaultValue
356
- : TControl extends readonly [infer First, ...unknown[]]
357
- ? OptionValue<First>
358
- : TControl extends ControlPrimitive
359
- ? TControl
360
- : unknown
361
-
362
- type OptionValue<TOption> = TOption extends SelectOption<infer TValue> ? TValue : TOption
363
-
364
- interface NormalizedControl {
365
- name: string
366
- definition: ControlDefinition
367
- type: FormFieldType
368
- sectionId: string
369
- viewId: string
370
- order: number
371
- }
18
+ ControlComponentBindingsConfig,
19
+ ControlSchema,
20
+ ControlSchemaOptions,
21
+ ControlValues,
22
+ UseControlSchemaReturn,
23
+ } from './controlSchemaTypes'
24
+
25
+ export type * from './controlSchemaTypes'
26
+
27
+ export {
28
+ mergeControlWorkspaceOptions,
29
+ } from './controlWorkspaceOptions'
30
+
31
+ export {
32
+ useControlWorkspace,
33
+ } from './useControlWorkspace'
34
+
35
+ export {
36
+ controlValuesToComponentBindings,
37
+ controlValuesToComponentBindingsById,
38
+ controlValuesToComponentProps,
39
+ } from './controlComponentBindings'
40
+
41
+ export {
42
+ controlsToFormSchema,
43
+ controlsToSectionFormSchema,
44
+ controlsToSectionFormSchemas,
45
+ controlsToSettingsSchema,
46
+ controlsToSidebarPanels,
47
+ controlsToTopBarSettingsConfig,
48
+ controlsToViewIds,
49
+ controlsToViewItems,
50
+ getDefaultControlView,
51
+ } from './controlSchemaAdapters'
52
+
53
+ export {
54
+ defineControlModel,
55
+ isControlModelBinding,
56
+ resolveControlModel,
57
+ } from './controlSchemaModel'
58
+
59
+ export {
60
+ defineDoseCalculatorControlProps,
61
+ defineDoseDesignControlModel,
62
+ defineWellPlateControlProps,
63
+ defineWellPlateDoseComponentBindings,
64
+ defineWellPlateDoseControlProps,
65
+ } from './controlSchemaDoseDesign'
372
66
 
373
67
  /** Preserve literal control keys while marking an object as a MINT control schema. */
374
68
  export function defineControls<TControls extends ControlSchema>(controls: TControls): TControls {
@@ -382,94 +76,6 @@ export function defineControlComponentBindings<TBindings extends ControlComponen
382
76
  return bindings
383
77
  }
384
78
 
385
- /** Create a complete workspace component binding from a simple controls data model for ControlWorkspaceView, generated forms, and sidebars. */
386
- export function defineControlModel(model: ControlModel): ControlModelBinding {
387
- const {
388
- controls: rootControls,
389
- sections: rootSections,
390
- views: modelViews,
391
- components,
392
- componentBindings,
393
- componentProps,
394
- componentPropsById,
395
- ...baseOptions
396
- } = model
397
- const resolvedComponentBindings = componentBindings ?? components
398
- const controls: ControlSchema = {}
399
- const views: Record<string, ControlViewConfig> = {}
400
- const sections: Record<string, ControlSectionConfig> = {}
401
-
402
- const defaultViewId = model.view ?? 'default'
403
- const defaultSectionId = model.section ?? 'controls'
404
-
405
- if (rootControls) {
406
- registerSectionOptions(sections, defaultSectionId, {
407
- id: defaultSectionId,
408
- label: model.sectionLabel,
409
- title: model.sectionLabel,
410
- columns: model.columns,
411
- })
412
- appendModelControls(controls, rootControls, defaultViewId, defaultSectionId)
413
- }
414
-
415
- for (const [sectionId, section] of Object.entries(rootSections ?? {})) {
416
- registerSectionOptions(sections, sectionId, controlModelSectionOptions(section))
417
- appendModelControls(controls, section.controls, defaultViewId, sectionId, section.sidebar)
418
- }
419
-
420
- for (const [viewId, view] of Object.entries(modelViews ?? {})) {
421
- const {
422
- controls: viewControls,
423
- sections: viewSections,
424
- section,
425
- sectionLabel,
426
- sectionDescription,
427
- ...viewConfig
428
- } = view
429
-
430
- views[viewId] = omitUndefined(viewConfig)
431
-
432
- if (viewControls) {
433
- const sectionId = section ?? `${viewId}-controls`
434
- const label = sectionLabel ?? view.label
435
- registerSectionOptions(sections, sectionId, {
436
- id: sectionId,
437
- label,
438
- title: label,
439
- description: sectionDescription,
440
- columns: model.columns,
441
- })
442
- appendModelControls(controls, viewControls, viewId, sectionId)
443
- }
444
-
445
- for (const [sectionKey, sectionConfig] of Object.entries(viewSections ?? {})) {
446
- const sectionId = sectionConfig.id ?? `${viewId}-${sectionKey}`
447
- registerSectionOptions(sections, sectionId, controlModelSectionOptions(sectionConfig))
448
- appendModelControls(controls, sectionConfig.controls, viewId, sectionId, sectionConfig.sidebar)
449
- }
450
- }
451
-
452
- const controlOptions: ControlWorkspaceOptions = {
453
- ...baseOptions,
454
- }
455
-
456
- if (Object.keys(views).length > 0) {
457
- controlOptions.views = views
458
- }
459
-
460
- if (Object.keys(sections).length > 0) {
461
- controlOptions.sections = sections
462
- }
463
-
464
- return {
465
- controls,
466
- controlOptions,
467
- ...(resolvedComponentBindings === undefined ? {} : { componentBindings: resolvedComponentBindings }),
468
- ...(componentProps === undefined ? {} : { componentProps }),
469
- ...(componentPropsById === undefined ? {} : { componentPropsById }),
470
- }
471
- }
472
-
473
79
  /** Build default values for a control schema, matching FormBuilder field defaults. */
474
80
  export function getControlDefaults<TControls extends ControlSchema>(
475
81
  controls: TControls,
@@ -481,380 +87,6 @@ export function getControlDefaults<TControls extends ControlSchema>(
481
87
  return values as ControlValues<TControls>
482
88
  }
483
89
 
484
- /** Map control workspace values into component props for direct `v-bind` usage. */
485
- export function controlValuesToComponentProps<TValues extends Record<string, unknown>>(
486
- values: TValues,
487
- mapping?: ControlComponentPropsMap<TValues>,
488
- ): Record<string, unknown> {
489
- if (mapping === undefined) return { ...values }
490
-
491
- if (Array.isArray(mapping)) {
492
- const props: Record<string, unknown> = {}
493
- for (const key of mapping) {
494
- props[key] = values[key]
495
- }
496
- return props
497
- }
498
-
499
- const props: Record<string, unknown> = {}
500
- for (const [prop, source] of Object.entries(mapping) as Array<[string, ControlComponentPropSource<TValues>]>) {
501
- props[prop] = typeof source === 'function' ? source(values) : values[source]
502
- }
503
- return props
504
- }
505
-
506
- /** Map control workspace values into named SDK component bindings for direct slot rendering. */
507
- export function controlValuesToComponentBindings<TValues extends Record<string, unknown>>(
508
- values: TValues,
509
- bindings?: ControlComponentBindingsConfig<TValues>,
510
- ): ControlComponentBinding[] {
511
- if (bindings === undefined) return []
512
-
513
- return normalizeControlComponentBindingConfigs(bindings).map(binding => ({
514
- id: binding.id,
515
- component: binding.component,
516
- props: controlValuesToComponentProps(values, binding.props),
517
- }))
518
- }
519
-
520
- /** Map control workspace values into SDK component bindings keyed by binding id. */
521
- export function controlValuesToComponentBindingsById<TValues extends Record<string, unknown>>(
522
- values: TValues,
523
- bindings?: ControlComponentBindingsConfig<TValues>,
524
- ): ControlComponentBindingsById {
525
- return Object.fromEntries(
526
- controlValuesToComponentBindings(values, bindings).map(binding => [binding.id, binding]),
527
- )
528
- }
529
-
530
- /** Return a default WellPlate prop mapping for generated control workspaces. */
531
- export function defineWellPlateControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
532
- options: WellPlateControlPropsOptions<TValues> = {},
533
- ): ControlComponentPropsMap<TValues> {
534
- const selectedWells = options.selectedWells ?? sourceKey<TValues>('selectedWells')
535
- const onUpdateModelValue = options.onUpdateModelValue === false
536
- ? undefined
537
- : options.onUpdateModelValue ?? updateControlValueSource(selectedWells)
538
-
539
- return compactComponentPropsMap<TValues>({
540
- modelValue: selectedWells,
541
- 'onUpdate:modelValue': onUpdateModelValue,
542
- format: options.format ?? sourceKey<TValues>('plateFormat'),
543
- wells: options.wells ?? sourceKey<TValues>('wells'),
544
- disabled: options.disabled ?? sourceKey<TValues>('disabled'),
545
- readonly: options.readonly ?? sourceKey<TValues>('readonly'),
546
- showLegend: options.showLegend,
547
- showSampleTypeIndicator: options.showSampleTypeIndicator,
548
- })
549
- }
550
-
551
- /** Return a default DoseCalculator prop mapping for generated control workspaces. */
552
- export function defineDoseCalculatorControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
553
- options: DoseCalculatorControlPropsOptions<TValues> = {},
554
- ): ControlComponentPropsMap<TValues> {
555
- const targetWells = options.targetWells ?? sourceKey<TValues>('selectedWells')
556
- const wells = options.wells ?? sourceKey<TValues>('wells')
557
- const onApplyToWells = options.onApplyToWells === false
558
- ? undefined
559
- : options.onApplyToWells ?? defaultDoseApplyHandler(wells, targetWells)
560
-
561
- return compactComponentPropsMap<TValues>({
562
- mode: options.mode ?? sourceKey<TValues>('doseMode'),
563
- targetWells,
564
- disabled: options.disabled ?? sourceKey<TValues>('disabled'),
565
- molecularWeight: options.molecularWeight,
566
- onApplyToWells,
567
- })
568
- }
569
-
570
- /** Return named WellPlate + DoseCalculator prop mappings for one dose-design control model. */
571
- export function defineWellPlateDoseControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(
572
- options: WellPlateDoseControlPropsOptions<TValues> = {},
573
- ): ControlComponentPropsByIdMap<TValues> {
574
- return {
575
- [options.plateId ?? 'plate']: defineWellPlateControlProps(options.plate),
576
- [options.doseId ?? 'dose']: defineDoseCalculatorControlProps(options.dose),
577
- }
578
- }
579
-
580
- /** Return named WellPlate + DoseCalculator component bindings for one dose-design control model. */
581
- export function defineWellPlateDoseComponentBindings<TValues extends Record<string, unknown> = Record<string, unknown>>(
582
- options: WellPlateDoseControlPropsOptions<TValues> = {},
583
- ): ControlComponentBindingsConfig<TValues> {
584
- return [
585
- {
586
- id: options.plateId ?? 'plate',
587
- component: 'WellPlate',
588
- props: defineWellPlateControlProps(options.plate),
589
- },
590
- {
591
- id: options.doseId ?? 'dose',
592
- component: 'DoseCalculator',
593
- props: defineDoseCalculatorControlProps(options.dose),
594
- },
595
- ]
596
- }
597
-
598
- /** Return a complete ControlWorkspaceView model for WellPlate + DoseCalculator dose design. */
599
- export function defineDoseDesignControlModel(
600
- options: DoseDesignControlModelOptions = {},
601
- ): ControlModelBinding {
602
- const viewId = options.viewId ?? 'design'
603
- const sectionId = options.sectionId ?? 'dose'
604
- const doseControls: ControlSchema = {
605
- selectedWells: {
606
- type: 'tags',
607
- label: 'Selected wells',
608
- default: [...(options.selectedWells ?? ['A1', 'A2'])],
609
- },
610
- plateFormat: {
611
- label: 'Plate format',
612
- default: options.plateFormat ?? 96,
613
- options: options.plateFormats ?? [96, 384],
614
- },
615
- doseMode: {
616
- label: 'Dose mode',
617
- default: options.doseMode ?? 'serial',
618
- options: options.doseModes ?? ['serial', 'dilution', 'conversion'],
619
- },
620
- disabled: {
621
- label: 'Disable tools',
622
- default: options.disabled ?? false,
623
- },
624
- }
625
-
626
- if (options.includeMolecularWeight) {
627
- doseControls.molecularWeight = {
628
- type: 'number',
629
- label: 'Molecular weight',
630
- default: options.molecularWeight ?? 300,
631
- min: 0,
632
- }
633
- }
634
-
635
- const componentProps: WellPlateDoseControlPropsOptions = {
636
- ...options.componentProps,
637
- dose: {
638
- ...(options.componentProps?.dose ?? {}),
639
- ...(options.includeMolecularWeight && options.componentProps?.dose?.molecularWeight === undefined
640
- ? { molecularWeight: 'molecularWeight' }
641
- : {}),
642
- },
643
- }
644
-
645
- return defineControlModel({
646
- componentBindings: defineWellPlateDoseComponentBindings(componentProps),
647
- componentPropsById: defineWellPlateDoseControlProps(componentProps),
648
- views: {
649
- [viewId]: {
650
- label: options.viewLabel ?? 'Design',
651
- sections: {
652
- [sectionId]: {
653
- label: options.sectionLabel ?? 'Dose design',
654
- description: options.sectionDescription ?? 'Well selection and dose calculator controls',
655
- controls: doseControls,
656
- },
657
- },
658
- },
659
- },
660
- })
661
- }
662
-
663
- function isControlModelBindingInput<TControls extends ControlSchema>(
664
- value: TControls | (ControlModelBinding & { controls: TControls }),
665
- ): value is ControlModelBinding & { controls: TControls } {
666
- return (
667
- typeof value === 'object'
668
- && value !== null
669
- && 'controls' in value
670
- && 'controlOptions' in value
671
- )
672
- }
673
-
674
- export function mergeControlWorkspaceOptions(
675
- base?: ControlWorkspaceOptions,
676
- override?: ControlWorkspaceOptions,
677
- ): ControlWorkspaceOptions {
678
- return {
679
- ...(base ?? {}),
680
- ...(override ?? {}),
681
- initialValues: {
682
- ...(base?.initialValues ?? {}),
683
- ...(override?.initialValues ?? {}),
684
- },
685
- topBarSettings: {
686
- ...(base?.topBarSettings ?? {}),
687
- ...(override?.topBarSettings ?? {}),
688
- },
689
- }
690
- }
691
-
692
- /** Convert a compact control schema into a FormBuilder schema. */
693
- export function controlsToFormSchema(
694
- controls: ControlSchema,
695
- options: ControlSchemaOptions = {},
696
- ): ControlFormSchema {
697
- const normalized = normalizeControls(controls, options)
698
- const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
699
- const sections = sectionIds.map((sectionId): FormSectionSchema => {
700
- const sectionControls = normalized.filter(control => control.sectionId === sectionId)
701
- const config = sectionConfig(sectionId, sectionControls, options)
702
- return {
703
- id: sectionId,
704
- title: config.title ?? config.label ?? humanize(sectionId),
705
- description: config.description,
706
- columns: config.columns ?? options.columns ?? 1,
707
- defaultOpen: config.defaultOpen,
708
- condition: config.condition,
709
- fields: sectionControls.map(controlToFormField),
710
- }
711
- })
712
-
713
- return {
714
- sections,
715
- submitLabel: options.submitLabel,
716
- cancelLabel: options.cancelLabel,
717
- showCancel: options.showCancel,
718
- }
719
- }
720
-
721
- /** Convert controls into AppSidebar panels grouped by view and section. */
722
- export function controlsToSidebarPanels(
723
- controls: ControlSchema,
724
- options: ControlSchemaOptions = {},
725
- ): Record<string, SidebarToolSection[]> {
726
- const normalized = normalizeControls(controls, options)
727
- .filter(control => isSidebarEnabled(control.definition.sidebar))
728
- const viewIds = orderedUnique(normalized.map(control => control.viewId))
729
- const panels: Record<string, SidebarToolSection[]> = {}
730
-
731
- for (const viewId of viewIds) {
732
- const viewControls = normalized.filter(control => control.viewId === viewId)
733
- const sectionIds = orderedUnique(viewControls.map(control => control.sectionId))
734
- panels[viewId] = sectionIds.map((sectionId): SidebarToolSection => {
735
- const sectionControls = viewControls.filter(control => control.sectionId === sectionId)
736
- const config = sectionConfig(sectionId, sectionControls, options)
737
- const sidebarConfig = firstSidebarConfig(sectionControls)
738
- return {
739
- id: sectionId,
740
- label: sidebarConfig?.label ?? config.label ?? config.title ?? humanize(sectionId),
741
- subtitle: sidebarConfig?.subtitle ?? config.subtitle,
742
- icon: sidebarConfig?.icon ?? config.icon,
743
- iconColor: sidebarConfig?.iconColor ?? config.iconColor,
744
- iconBg: sidebarConfig?.iconBg ?? config.iconBg,
745
- defaultOpen: sidebarConfig?.defaultOpen ?? config.defaultOpen,
746
- showToggle: sidebarConfig?.showToggle ?? config.showToggle,
747
- }
748
- })
749
- }
750
-
751
- return panels
752
- }
753
-
754
- /** Convert controls into a SettingsModal schema grouped by the same sections. */
755
- export function controlsToSettingsSchema(
756
- controls: ControlSchema,
757
- options: ControlSchemaOptions = {},
758
- ): SettingsModalSchema {
759
- const normalized = normalizeControls(controls, options)
760
- const sectionIds = orderedUnique(normalized.map(control => control.sectionId))
761
-
762
- return {
763
- groups: sectionIds.map((sectionId) => {
764
- const sectionControls = normalized.filter(control => control.sectionId === sectionId)
765
- const config = sectionConfig(sectionId, sectionControls, options)
766
- return {
767
- id: sectionId,
768
- label: config.label ?? config.title ?? humanize(sectionId),
769
- description: config.description ?? config.subtitle,
770
- icon: typeof config.icon === 'string' ? config.icon : undefined,
771
- fields: sectionControls.map(controlToFormField),
772
- columns: config.columns ?? options.columns ?? 1,
773
- condition: config.condition,
774
- access: config.access,
775
- visibleFor: config.visibleFor,
776
- requiresAdmin: config.requiresAdmin,
777
- permissions: config.permissions,
778
- anyPermissions: config.anyPermissions,
779
- }
780
- }),
781
- }
782
- }
783
-
784
- /** Convert controls into an AppTopBar settingsConfig object that passes compact controls through to SettingsModal. */
785
- export function controlsToTopBarSettingsConfig(
786
- controls: ControlSchema,
787
- options: ControlSchemaOptions = {},
788
- config: Omit<TopBarSettingsConfig, 'schema' | 'controls' | 'controlOptions'> = {},
789
- ): TopBarSettingsConfig {
790
- return {
791
- ...config,
792
- controls,
793
- controlOptions: options,
794
- }
795
- }
796
-
797
- /** Return generated control view IDs that have at least one sidebar panel. */
798
- export function controlsToViewIds(
799
- controls: ControlSchema,
800
- options: ControlSchemaOptions = {},
801
- ): string[] {
802
- return controlsToViewItems(controls, options).map(item => item.id)
803
- }
804
-
805
- /** Return AppTopBar pillNav-compatible view items for switching generated control sidebars. */
806
- export function controlsToViewItems(
807
- controls: ControlSchema,
808
- options: ControlSchemaOptions = {},
809
- ): PillNavItem[] {
810
- return Object.entries(controlsToSidebarPanels(controls, options))
811
- .filter(([, sections]) => sections.length > 0)
812
- .map(([id]) => controlViewItem(id, options))
813
- }
814
-
815
- /** Return the first generated sidebar view ID, or an empty string when controls render no sidebar panels. */
816
- export function getDefaultControlView(
817
- controls: ControlSchema,
818
- options: ControlSchemaOptions = {},
819
- ): string {
820
- return controlsToViewIds(controls, options)[0] ?? ''
821
- }
822
-
823
- /** Return a headerless single-section FormBuilder schema for rendering inside an AppSidebar section slot. */
824
- export function controlsToSectionFormSchema(
825
- controls: ControlSchema,
826
- sectionId: string,
827
- options: ControlSchemaOptions = {},
828
- ): ControlFormSchema {
829
- const schema = controlsToFormSchema(controls, options)
830
- return {
831
- sections: schema.sections
832
- .filter(section => section.id === sectionId)
833
- .map(section => ({ ...section, title: '', description: undefined })),
834
- submitLabel: schema.submitLabel,
835
- cancelLabel: schema.cancelLabel,
836
- showCancel: schema.showCancel,
837
- }
838
- }
839
-
840
- /** Return headerless FormBuilder schemas keyed by section ID for AppSidebar auto-rendering. */
841
- export function controlsToSectionFormSchemas(
842
- controls: ControlSchema,
843
- options: ControlSchemaOptions = {},
844
- ): Record<string, ControlFormSchema> {
845
- const schema = controlsToFormSchema(controls, options)
846
- const schemas: Record<string, ControlFormSchema> = {}
847
- for (const section of schema.sections) {
848
- schemas[section.id] = {
849
- sections: [{ ...section, title: '', description: undefined }],
850
- submitLabel: schema.submitLabel,
851
- cancelLabel: schema.cancelLabel,
852
- showCancel: schema.showCancel,
853
- }
854
- }
855
- return schemas
856
- }
857
-
858
90
  /** Prepare FormBuilder, SettingsModal, AppTopBar settings, AppSidebar, and initial values from one compact control model. */
859
91
  export function useControlSchema<TControls extends ControlSchema>(
860
92
  controls: TControls,
@@ -901,483 +133,3 @@ export function useControlSchema<TControls extends ControlSchema>(
901
133
  sectionSchema: (sectionId: string) => controlsToSectionFormSchema(controls, sectionId, options),
902
134
  }
903
135
  }
904
-
905
- /** Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model. */
906
- export function useControlWorkspace<TControls extends ControlSchema>(
907
- controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),
908
- options: ControlWorkspaceOptions = {},
909
- ): UseControlWorkspaceReturn<TControls> {
910
- const model = isControlModelBindingInput<TControls>(controlsOrModel) ? controlsOrModel : undefined
911
- const controls: TControls = model ? model.controls : controlsOrModel as TControls
912
- const workspaceOptions = model
913
- ? mergeControlWorkspaceOptions(model.controlOptions, options)
914
- : options
915
- const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions
916
- const schema = useControlSchema(controls, schemaOptions)
917
- const activeView = ref(schema.defaultView)
918
- const values = reactive({
919
- ...schema.initialValues,
920
- ...(initialValues ?? {}),
921
- }) as ControlValues<TControls> & Record<string, unknown>
922
-
923
- function setActiveView(viewId: string) {
924
- syncActiveView(viewId)
925
- }
926
-
927
- function syncActiveView(viewId: string) {
928
- if (!schema.viewIds.includes(viewId)) return
929
- if (activeView.value !== viewId) activeView.value = viewId
930
- if (sidebar.activeView !== viewId) sidebar.activeView = viewId
931
- if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId
932
- }
933
-
934
- function setValues(nextValues: Record<string, unknown>) {
935
- Object.assign(values, nextValues)
936
- }
937
-
938
- function resetValues(nextValues: Record<string, unknown> = {}) {
939
- replaceRecord(values, {
940
- ...schema.initialValues,
941
- ...nextValues,
942
- })
943
- }
944
-
945
- function getComponentProps(
946
- mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,
947
- ): Record<string, unknown> {
948
- return controlValuesToComponentProps(values, mapping)
949
- }
950
-
951
- function getComponentPropsById(
952
- mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,
953
- ): Record<string, Record<string, unknown>> {
954
- if (mappings === undefined) return {}
955
-
956
- return Object.fromEntries(
957
- Object.entries(mappings).map(([id, mapping]) => [
958
- id,
959
- controlValuesToComponentProps(values, mapping),
960
- ]),
961
- )
962
- }
963
-
964
- function getComponentBindings(
965
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
966
- ): ControlComponentBinding[] {
967
- return controlValuesToComponentBindings(values, bindings)
968
- }
969
-
970
- function getComponentBindingsById(
971
- bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,
972
- ): ControlComponentBindingsById {
973
- return controlValuesToComponentBindingsById(values, bindings)
974
- }
975
- const componentProps = computed(() => (
976
- model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)
977
- ))
978
- const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))
979
- const componentBindings = computed(() => getComponentBindings(model?.componentBindings))
980
- const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))
981
- const form = {
982
- ...schema.form,
983
- modelValue: values,
984
- 'onUpdate:modelValue': setValues,
985
- } as ControlWorkspaceFormBinding
986
-
987
- const topBarSettingsConfig: TopBarSettingsConfig = {
988
- ...schema.topBarSettingsConfig,
989
- ...(topBarSettings ?? {}),
990
- values,
991
- }
992
- const sidebar = reactive({
993
- ...schema.sidebar,
994
- activeView: activeView.value,
995
- modelValue: values,
996
- 'onUpdate:modelValue': setValues,
997
- values,
998
- 'onUpdate:values': setValues,
999
- }) as ControlWorkspaceSidebarBinding
1000
- const pillNav = reactive({
1001
- items: schema.viewItems,
1002
- currentItemId: activeView.value,
1003
- onSelect: (item: PillNavItem) => setActiveView(item.id),
1004
- }) as ControlWorkspacePillNavBinding
1005
- const topBarSettingsBinding = {
1006
- showSettings: true,
1007
- settingsConfig: topBarSettingsConfig,
1008
- onSettingsValuesChange: setValues,
1009
- } as ControlWorkspaceTopBarSettingsBinding
1010
- const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({
1011
- pillNav: pillNav.items,
1012
- currentPillId: pillNav.currentItemId,
1013
- onPillSelect: pillNav.onSelect,
1014
- ...topBarSettingsBinding,
1015
- }))
1016
- const bindings: ControlWorkspaceComponentBindings = {
1017
- form,
1018
- sidebar,
1019
- topBar: topBarProps,
1020
- topBarSettings: topBarSettingsBinding,
1021
- pillNav,
1022
- componentBindings,
1023
- componentBindingsById,
1024
- componentProps,
1025
- componentPropsById,
1026
- }
1027
-
1028
- watch(activeView, syncActiveView, { flush: 'sync' })
1029
- watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })
1030
- watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })
1031
-
1032
- return {
1033
- ...schema,
1034
- schema,
1035
- values,
1036
- activeView,
1037
- topBarSettingsConfig,
1038
- form,
1039
- sidebar,
1040
- topBar: topBarProps,
1041
- pillNav,
1042
- topBarSettings: topBarSettingsBinding,
1043
- bindings,
1044
- componentBindings,
1045
- componentBindingsById,
1046
- componentProps,
1047
- componentPropsById,
1048
- setActiveView,
1049
- setValues,
1050
- resetValues,
1051
- getComponentProps,
1052
- getComponentPropsById,
1053
- getComponentBindings,
1054
- getComponentBindingsById,
1055
- }
1056
- }
1057
-
1058
- function normalizeControls(
1059
- controls: ControlSchema,
1060
- options: ControlSchemaOptions = {},
1061
- ): NormalizedControl[] {
1062
- return Object.entries(controls)
1063
- .map(([name, input], index): NormalizedControl => {
1064
- const definition = normalizeControlDefinition(input)
1065
- const type = definition.type ?? inferControlType(definition)
1066
- return {
1067
- name,
1068
- definition,
1069
- type,
1070
- sectionId: definition.section ?? options.section ?? 'controls',
1071
- viewId: definition.view ?? options.view ?? 'default',
1072
- order: definition.order ?? index,
1073
- }
1074
- })
1075
- .sort((a, b) => a.order - b.order)
1076
- }
1077
-
1078
- function normalizeControlDefinition(input: ControlInput): ControlDefinition {
1079
- if (isControlOptionArray(input)) {
1080
- if (input.length === 0) return { type: 'tags', default: [] }
1081
- return {
1082
- default: optionValue(input[0]),
1083
- options: input,
1084
- }
1085
- }
1086
-
1087
- if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {
1088
- return { default: input }
1089
- }
1090
-
1091
- return input
1092
- }
1093
-
1094
- function appendModelControls(
1095
- target: ControlSchema,
1096
- source: ControlSchema,
1097
- viewId: string,
1098
- sectionId: string,
1099
- sidebar?: boolean | ControlSidebarConfig,
1100
- ): void {
1101
- for (const [name, input] of Object.entries(source)) {
1102
- if (Object.prototype.hasOwnProperty.call(target, name)) {
1103
- throw new Error(
1104
- `Duplicate control "${name}" in defineControlModel(). Control names must be unique across views and sections.`,
1105
- )
1106
- }
1107
-
1108
- const definition = normalizeControlDefinition(input)
1109
- target[name] = omitUndefined({
1110
- ...definition,
1111
- view: definition.view ?? viewId,
1112
- section: definition.section ?? sectionId,
1113
- sidebar: definition.sidebar ?? sidebar,
1114
- })
1115
- }
1116
- }
1117
-
1118
- function controlModelSectionOptions(section: ControlModelSectionConfig): ControlSectionConfig {
1119
- const { controls: _controls, sidebar: _sidebar, ...options } = section
1120
- return omitUndefined(options)
1121
- }
1122
-
1123
- function registerSectionOptions(
1124
- target: Record<string, ControlSectionConfig>,
1125
- sectionId: string,
1126
- options: ControlSectionConfig,
1127
- ): void {
1128
- target[sectionId] = omitUndefined({
1129
- ...(target[sectionId] ?? {}),
1130
- ...options,
1131
- id: sectionId,
1132
- })
1133
- }
1134
-
1135
- function isControlOptionArray(input: ControlInput): input is readonly ControlOption[] {
1136
- return Array.isArray(input)
1137
- }
1138
-
1139
- function inferControlType(definition: ControlDefinition): FormFieldType {
1140
- const value = definition.default ?? definition.defaultValue
1141
- if (definition.options?.length) return Array.isArray(value) ? 'multiselect' : 'select'
1142
- if (typeof value === 'boolean') return 'toggle'
1143
- if (typeof value === 'number') return 'number'
1144
- if (Array.isArray(value)) return 'tags'
1145
- return 'text'
1146
- }
1147
-
1148
- function defaultValueForControl(definition: ControlDefinition, type: FormFieldType): unknown {
1149
- if (definition.default !== undefined) return definition.default
1150
- if (definition.defaultValue !== undefined) return definition.defaultValue
1151
- return getTypeDefault(type)
1152
- }
1153
-
1154
- function controlToFormField(control: NormalizedControl): FormFieldSchema {
1155
- const { name, definition, type } = control
1156
- const props = fieldProps(definition)
1157
- return {
1158
- name,
1159
- label: definition.label ?? humanize(name),
1160
- type,
1161
- defaultValue: defaultValueForControl(definition, type),
1162
- placeholder: definition.placeholder,
1163
- hint: definition.hint,
1164
- size: definition.size,
1165
- disabled: definition.disabled,
1166
- readonly: definition.readonly,
1167
- validation: validationForControl(definition),
1168
- condition: definition.condition,
1169
- access: definition.access,
1170
- visibleFor: definition.visibleFor,
1171
- requiresAdmin: definition.requiresAdmin,
1172
- permissions: definition.permissions,
1173
- anyPermissions: definition.anyPermissions,
1174
- colSpan: definition.colSpan,
1175
- props,
1176
- }
1177
- }
1178
-
1179
- function fieldProps(definition: ControlDefinition): Record<string, unknown> {
1180
- const props: Record<string, unknown> = {}
1181
- if (definition.min !== undefined) props.min = numericValue(definition.min)
1182
- if (definition.max !== undefined) props.max = numericValue(definition.max)
1183
- if (definition.options) props.options = definition.options.map(normalizeOption)
1184
- return { ...props, ...(definition.props ?? {}) }
1185
- }
1186
-
1187
- function validationForControl(definition: ControlDefinition): FieldValidation | undefined {
1188
- const validation: FieldValidation = { ...(definition.validation ?? {}) }
1189
- if (definition.required !== undefined) validation.required = definition.required
1190
- if (definition.min !== undefined) validation.min = definition.min
1191
- if (definition.max !== undefined) validation.max = definition.max
1192
- if (definition.minLength !== undefined) validation.minLength = definition.minLength
1193
- if (definition.maxLength !== undefined) validation.maxLength = definition.maxLength
1194
- if (definition.email !== undefined) validation.email = definition.email
1195
- if (definition.pattern !== undefined) validation.pattern = definition.pattern
1196
- return Object.keys(validation).length > 0 ? validation : undefined
1197
- }
1198
-
1199
- function sectionConfig(
1200
- sectionId: string,
1201
- controls: NormalizedControl[],
1202
- options: ControlSchemaOptions,
1203
- ): ControlSectionConfig {
1204
- const configured = options.sections?.[sectionId]
1205
- const first = controls[0]?.definition
1206
- return {
1207
- ...configured,
1208
- id: sectionId,
1209
- label: configured?.label ?? first?.sectionLabel,
1210
- title: configured?.title ?? first?.sectionLabel,
1211
- description: configured?.description ?? first?.sectionDescription,
1212
- subtitle: configured?.subtitle ?? first?.sectionSubtitle,
1213
- }
1214
- }
1215
-
1216
- function firstSidebarConfig(controls: NormalizedControl[]): ControlSidebarConfig | undefined {
1217
- for (const control of controls) {
1218
- const sidebar = control.definition.sidebar
1219
- if (sidebar && typeof sidebar === 'object' && sidebar.enabled !== false) return sidebar
1220
- }
1221
- return undefined
1222
- }
1223
-
1224
- function isSidebarEnabled(sidebar: ControlDefinition['sidebar']): boolean {
1225
- if (sidebar === false) return false
1226
- if (sidebar && typeof sidebar === 'object') return sidebar.enabled !== false
1227
- return true
1228
- }
1229
-
1230
- function normalizeOption(option: ControlOption): SelectOption<unknown> {
1231
- if (typeof option === 'object' && option !== null && 'label' in option) {
1232
- return option
1233
- }
1234
- return {
1235
- value: option,
1236
- label: humanize(String(option)),
1237
- }
1238
- }
1239
-
1240
- function optionValue(option: ControlOption): ControlOptionValue | unknown {
1241
- if (typeof option === 'object' && option !== null && 'value' in option) {
1242
- return option.value
1243
- }
1244
- return option
1245
- }
1246
-
1247
- function compactComponentPropsMap<TValues extends Record<string, unknown>>(
1248
- mapping: Record<string, ControlComponentPropSource<TValues> | undefined>,
1249
- ): ControlComponentPropsMap<TValues> {
1250
- return Object.fromEntries(
1251
- Object.entries(mapping).filter((entry): entry is [string, ControlComponentPropSource<TValues>] =>
1252
- entry[1] !== undefined
1253
- ),
1254
- )
1255
- }
1256
-
1257
- function normalizeControlComponentBindingConfigs<TValues extends Record<string, unknown>>(
1258
- bindings: ControlComponentBindingsConfig<TValues>,
1259
- ): Array<Required<Pick<ControlComponentBindingConfig<TValues>, 'id' | 'component'>> & Pick<ControlComponentBindingConfig<TValues>, 'props'>> {
1260
- if (Array.isArray(bindings)) {
1261
- const usedIds = new Map<string, number>()
1262
- return bindings.map(binding => ({
1263
- id: uniqueComponentBindingId(binding.id ?? binding.component, usedIds),
1264
- component: binding.component,
1265
- props: binding.props,
1266
- }))
1267
- }
1268
-
1269
- return Object.entries(bindings).map(([id, binding]) => ({
1270
- id,
1271
- component: binding.component,
1272
- props: binding.props,
1273
- }))
1274
- }
1275
-
1276
- function uniqueComponentBindingId(id: string, usedIds: Map<string, number>): string {
1277
- const count = usedIds.get(id) ?? 0
1278
- usedIds.set(id, count + 1)
1279
- return count === 0 ? id : `${id}-${count + 1}`
1280
- }
1281
-
1282
- function sourceKey<TValues extends Record<string, unknown>>(key: string): keyof TValues & string {
1283
- return key as keyof TValues & string
1284
- }
1285
-
1286
- function updateControlValueSource<TValues extends Record<string, unknown>>(
1287
- source: ControlComponentPropSource<TValues>,
1288
- ): ((values: TValues) => (value: string[]) => void) | undefined {
1289
- if (typeof source !== 'string') return undefined
1290
- return values => (value: string[]) => {
1291
- const writableValues = values as Record<string, unknown>
1292
- writableValues[source] = value
1293
- }
1294
- }
1295
-
1296
- function defaultDoseApplyHandler<TValues extends Record<string, unknown>>(
1297
- wells: ControlComponentPropSource<TValues>,
1298
- targetWells: ControlComponentPropSource<TValues>,
1299
- ): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {
1300
- if (wells === targetWells) return undefined
1301
- return updateWellsFromDoseResults(wells)
1302
- }
1303
-
1304
- function updateWellsFromDoseResults<TValues extends Record<string, unknown>>(
1305
- source: ControlComponentPropSource<TValues>,
1306
- ): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {
1307
- if (typeof source !== 'string') return undefined
1308
- return values => (results: WellConcentration[]) => {
1309
- const writableValues = values as Record<string, unknown>
1310
- const currentWells = recordValue(writableValues[source])
1311
- const nextWells: Record<string, Record<string, unknown>> = {}
1312
- for (const [wellId, well] of Object.entries(currentWells)) {
1313
- nextWells[wellId] = recordValue(well)
1314
- }
1315
-
1316
- for (const result of results) {
1317
- const existing = recordValue(nextWells[result.wellId])
1318
- const metadata = recordValue(existing.metadata)
1319
- nextWells[result.wellId] = {
1320
- ...existing,
1321
- state: 'filled',
1322
- value: result.concentration.value,
1323
- metadata: {
1324
- ...metadata,
1325
- concentration: result.concentration,
1326
- ...(result.volume === undefined ? {} : { volume: result.volume }),
1327
- },
1328
- }
1329
- }
1330
-
1331
- writableValues[source] = nextWells
1332
- }
1333
- }
1334
-
1335
- function recordValue(value: unknown): Record<string, unknown> {
1336
- return typeof value === 'object' && value !== null && !Array.isArray(value)
1337
- ? value as Record<string, unknown>
1338
- : {}
1339
- }
1340
-
1341
- function numericValue(value: number | { value: number; message: string }): number {
1342
- return typeof value === 'number' ? value : value.value
1343
- }
1344
-
1345
- function orderedUnique(values: string[]): string[] {
1346
- return [...new Set(values)]
1347
- }
1348
-
1349
- function controlViewItem(viewId: string, options: ControlSchemaOptions): PillNavItem {
1350
- const config = options.views?.[viewId]
1351
- return {
1352
- id: viewId,
1353
- label: config?.label ?? humanize(viewId),
1354
- ...(config?.icon !== undefined ? { icon: config.icon } : {}),
1355
- ...(config?.to !== undefined ? { to: config.to } : {}),
1356
- ...(config?.href !== undefined ? { href: config.href } : {}),
1357
- ...(config?.disabled !== undefined ? { disabled: config.disabled } : {}),
1358
- ...(config?.children !== undefined ? { children: config.children } : {}),
1359
- }
1360
- }
1361
-
1362
- function replaceRecord(target: Record<string, unknown>, values: Record<string, unknown>) {
1363
- for (const key of Object.keys(target)) {
1364
- delete target[key]
1365
- }
1366
- Object.assign(target, values)
1367
- }
1368
-
1369
- function omitUndefined<T extends object>(record: T): T {
1370
- const next: Record<string, unknown> = {}
1371
- for (const [key, value] of Object.entries(record as Record<string, unknown>)) {
1372
- if (value !== undefined) next[key] = value
1373
- }
1374
- return next as T
1375
- }
1376
-
1377
- function humanize(value: string): string {
1378
- return value
1379
- .replace(/[_-]+/g, ' ')
1380
- .replace(/([a-z])([A-Z])/g, '$1 $2')
1381
- .trim()
1382
- .replace(/\w\S*/g, word => word.charAt(0).toUpperCase() + word.slice(1))
1383
- }