@morscherlab/mint-sdk 1.2.0-beta.7 → 1.2.0-beta.9

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 (307) hide show
  1. package/README.md +30 -0
  2. package/dist/{ExperimentPopover-CfOdh5Rm.js → ExperimentPopover-oL0fg_A0.js} +5 -3
  3. package/dist/ExperimentPopover-oL0fg_A0.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DvIagrxY.js → ExperimentSelectorModal-BeEOomw_.js} +4 -4
  5. package/dist/ExperimentSelectorModal-BeEOomw_.js.map +1 -0
  6. package/dist/{SettingsModal-W3TYfnP9.js → SettingsModal-Dphh3RrI.js} +4 -4
  7. package/dist/SettingsModal-Dphh3RrI.js.map +1 -0
  8. package/dist/{EmptyState-NBqf2_8z.js → Skeleton-DxtwJ5gt.js} +110 -92
  9. package/dist/Skeleton-DxtwJ5gt.js.map +1 -0
  10. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  11. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  12. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  13. package/dist/components/ActionMenu.vue.d.ts +1 -1
  14. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  15. package/dist/components/AuditTrail.vue.d.ts +13 -0
  16. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  17. package/dist/components/DataFrame.vue.d.ts +14 -2
  18. package/dist/components/DatePicker.vue.d.ts +1 -1
  19. package/dist/components/DateTimePicker.vue.d.ts +2 -0
  20. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  21. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  22. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  23. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  24. package/dist/components/ProgressBar.vue.d.ts +1 -1
  25. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  26. package/dist/components/ReagentList.vue.d.ts +29 -1
  27. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  28. package/dist/components/SampleSelector.drag.d.ts +13 -0
  29. package/dist/components/SampleSelector.tree.d.ts +2 -0
  30. package/dist/components/SampleSelector.vue.d.ts +34 -1
  31. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  32. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -0
  33. package/dist/components/TimePicker.vue.d.ts +1 -0
  34. package/dist/components/WellPlate.geometry.d.ts +15 -0
  35. package/dist/components/WellPlate.interaction.d.ts +13 -0
  36. package/dist/components/WellPlate.vue.d.ts +29 -0
  37. package/dist/components/index.js +6 -6
  38. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  39. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  40. package/dist/{components-B80gV0P6.js → components-CgAUzF8F.js} +1930 -1688
  41. package/dist/components-CgAUzF8F.js.map +1 -0
  42. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  43. package/dist/composables/index.d.ts +1 -0
  44. package/dist/composables/index.js +9 -9
  45. package/dist/composables/useDropdownState.d.ts +18 -2
  46. package/dist/composables/useEventStream.d.ts +9 -0
  47. package/dist/composables/useListReorder.d.ts +90 -0
  48. package/dist/composables/useMenuKeyboard.d.ts +2 -2
  49. package/dist/composables/usePluginConfig.d.ts +3 -1
  50. package/dist/composables/useRequestSyncState.d.ts +42 -2
  51. package/dist/composables/useScheduleDrag.d.ts +1 -0
  52. package/dist/{composables-C8mmD5ta.js → composables-B_pia3hO.js} +13 -69
  53. package/dist/composables-B_pia3hO.js.map +1 -0
  54. package/dist/{useApi-CDBq6z23.js → errors-_W0-LbA6.js} +102 -3
  55. package/dist/errors-_W0-LbA6.js.map +1 -0
  56. package/dist/{experiment-Y9Iz7KYi.js → experiment-Cwl9AYxw.js} +3 -8
  57. package/dist/experiment-Cwl9AYxw.js.map +1 -0
  58. package/dist/experiment-utils-DV3DrvE_.js.map +1 -1
  59. package/dist/index.js +14 -14
  60. package/dist/install.js +2 -7
  61. package/dist/install.js.map +1 -1
  62. package/dist/permissions.d.ts +42 -1
  63. package/dist/permissions.js +20 -10
  64. package/dist/permissions.js.map +1 -1
  65. package/dist/stores/index.d.ts +1 -1
  66. package/dist/stores/index.js +3 -3
  67. package/dist/stores/settings.d.ts +31 -1
  68. package/dist/styles.css +9572 -27877
  69. package/dist/templates/index.js +2 -4
  70. package/dist/{templates-CK72aKO1.js → templates-Qq113pyZ.js} +291 -85
  71. package/dist/templates-Qq113pyZ.js.map +1 -0
  72. package/dist/{useControlSchema-_OVhavKq.js → useControlSchema-aMZlb4Sc.js} +197 -1089
  73. package/dist/useControlSchema-aMZlb4Sc.js.map +1 -0
  74. package/dist/{useDropdownState-D5G4UvWd.js → useDropdownState-DitCtrTT.js} +21 -5
  75. package/dist/useDropdownState-DitCtrTT.js.map +1 -0
  76. package/dist/{useExperimentSelector-DSEckf_g.js → useExperimentSelector-I8HC8hUu.js} +3 -3
  77. package/dist/{useExperimentSelector-DSEckf_g.js.map → useExperimentSelector-I8HC8hUu.js.map} +1 -1
  78. package/dist/{useFormBuilder-Bd714C7y.js → useFormBuilder-TCxNnqeb.js} +2 -2
  79. package/dist/{useFormBuilder-Bd714C7y.js.map → useFormBuilder-TCxNnqeb.js.map} +1 -1
  80. package/dist/{useProtocolTemplates-Dq5Pzwyd.js → useProtocolTemplates-BmX_iVBR.js} +185 -157
  81. package/dist/useProtocolTemplates-BmX_iVBR.js.map +1 -0
  82. package/dist/utils/color.d.ts +13 -0
  83. package/dist/utils/errors.d.ts +9 -0
  84. package/package.json +1 -1
  85. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  86. package/src/__tests__/components/DataFrame.test.ts +183 -11
  87. package/src/__tests__/components/DataStates.test.ts +176 -0
  88. package/src/__tests__/components/DatePicker.test.ts +76 -0
  89. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  90. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  91. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  92. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  93. package/src/__tests__/components/RackEditor.test.ts +35 -0
  94. package/src/__tests__/components/ReagentList.test.ts +64 -2
  95. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  96. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  97. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  98. package/src/__tests__/components/SegmentedControl.test.ts +88 -0
  99. package/src/__tests__/components/TimePicker.test.ts +61 -0
  100. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  101. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  102. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  103. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  104. package/src/__tests__/stores/settings.test.ts +71 -1
  105. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  106. package/src/__tests__/utils/permissions.test.ts +68 -0
  107. package/src/components/ActionMenu.vue +45 -88
  108. package/src/components/AlertBox.vue +0 -4
  109. package/src/components/AppAvatarMenu.vue +2 -14
  110. package/src/components/AppLayout.vue +0 -4
  111. package/src/components/AppPluginSwitcher.story.vue +87 -0
  112. package/src/components/AppPluginSwitcher.vue +2 -5
  113. package/src/components/AppSidebar.vue +0 -4
  114. package/src/components/AppToastContainer.vue +6 -8
  115. package/src/components/AppTopBar.vue +0 -4
  116. package/src/components/ArtifactSaveDialog.vue +0 -4
  117. package/src/components/ArtifactSelectorModal.vue +0 -4
  118. package/src/components/AuditTrail.story.vue +18 -0
  119. package/src/components/AuditTrail.vue +27 -7
  120. package/src/components/AutoGroupModal.vue +0 -4
  121. package/src/components/Avatar.vue +0 -4
  122. package/src/components/BaseButton.vue +0 -4
  123. package/src/components/BaseCheckbox.vue +0 -4
  124. package/src/components/BaseInput.vue +0 -4
  125. package/src/components/BaseModal.vue +0 -4
  126. package/src/components/BasePill.vue +0 -4
  127. package/src/components/BaseRadioGroup.vue +0 -4
  128. package/src/components/BaseSelect.vue +0 -4
  129. package/src/components/BaseSlider.vue +0 -4
  130. package/src/components/BaseTabs.vue +0 -4
  131. package/src/components/BaseTextarea.vue +0 -4
  132. package/src/components/BaseToggle.vue +0 -4
  133. package/src/components/BatchProgressList.story.vue +18 -0
  134. package/src/components/BatchProgressList.vue +32 -4
  135. package/src/components/Breadcrumb.vue +0 -4
  136. package/src/components/Calendar.vue +0 -4
  137. package/src/components/ChartContainer.story.vue +1 -1
  138. package/src/components/ChartContainer.vue +0 -4
  139. package/src/components/ChemicalFormula.vue +0 -4
  140. package/src/components/CollapsibleCard.vue +0 -4
  141. package/src/components/ColorSlider.vue +0 -4
  142. package/src/components/ConcentrationInput.vue +0 -4
  143. package/src/components/ConfirmDialog.vue +0 -4
  144. package/src/components/DataFrame.story.vue +14 -0
  145. package/src/components/DataFrame.vue +97 -23
  146. package/src/components/DatePicker.vue +73 -27
  147. package/src/components/DateTimePicker.vue +45 -17
  148. package/src/components/Divider.vue +0 -4
  149. package/src/components/DoseCalculator.vue +0 -4
  150. package/src/components/DropdownButton.vue +2 -14
  151. package/src/components/EmptyState.vue +0 -4
  152. package/src/components/ExperimentCodeBadge.vue +0 -4
  153. package/src/components/ExperimentDataViewer.story.vue +3 -0
  154. package/src/components/ExperimentDataViewer.vue +33 -13
  155. package/src/components/ExperimentPopover.vue +2 -5
  156. package/src/components/ExperimentSelectorModal.vue +0 -4
  157. package/src/components/ExperimentTimeline.story.vue +18 -0
  158. package/src/components/ExperimentTimeline.vue +81 -75
  159. package/src/components/FileUploader.vue +0 -4
  160. package/src/components/FitPanel.vue +0 -4
  161. package/src/components/FormActions.story.vue +96 -0
  162. package/src/components/FormActions.vue +0 -4
  163. package/src/components/FormBuilder.vue +0 -4
  164. package/src/components/FormField.vue +0 -4
  165. package/src/components/FormulaInput.vue +0 -4
  166. package/src/components/GeneratedPathInput.story.vue +68 -0
  167. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  168. package/src/components/GeneratedPlotlyResult.vue +3 -3
  169. package/src/components/GeneratedPluginView.story.vue +145 -0
  170. package/src/components/GeneratedPluginView.vue +10 -10
  171. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  172. package/src/components/GeneratedResultRenderer.vue +4 -4
  173. package/src/components/GroupAssigner.vue +67 -5
  174. package/src/components/IconButton.vue +0 -4
  175. package/src/components/InstrumentAlertLog.vue +0 -4
  176. package/src/components/InstrumentStateBadge.vue +0 -4
  177. package/src/components/InstrumentStatusCard.vue +0 -4
  178. package/src/components/JobsStatusTray.vue +0 -4
  179. package/src/components/LcmsSequenceTable.vue +81 -50
  180. package/src/components/LoadingSpinner.vue +0 -4
  181. package/src/components/MobileSupportGate.vue +0 -4
  182. package/src/components/MoleculeInput.vue +0 -4
  183. package/src/components/MultiSelect.vue +0 -4
  184. package/src/components/NumberInput.vue +0 -4
  185. package/src/components/PlateMapEditor.vue +3 -14
  186. package/src/components/PluginIcon.vue +0 -4
  187. package/src/components/ProgressBar.vue +0 -4
  188. package/src/components/ProtocolStepEditor.vue +2 -4
  189. package/src/components/RackEditor.vue +51 -70
  190. package/src/components/ReagentEditor.vue +0 -4
  191. package/src/components/ReagentList.story.vue +18 -0
  192. package/src/components/ReagentList.vue +127 -82
  193. package/src/components/ResourceCard.vue +0 -4
  194. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  195. package/src/components/RuntimeUpdateNotice.vue +4 -4
  196. package/src/components/SampleHierarchyTree.story.vue +18 -0
  197. package/src/components/SampleHierarchyTree.vue +32 -9
  198. package/src/components/SampleLegend.vue +2 -8
  199. package/src/components/SampleSelector.drag.ts +51 -0
  200. package/src/components/SampleSelector.story.vue +6 -0
  201. package/src/components/SampleSelector.tree.ts +2 -0
  202. package/src/components/SampleSelector.vue +49 -10
  203. package/src/components/SampleSelectorGroupNode.vue +19 -0
  204. package/src/components/ScheduleCalendar.story.vue +6 -0
  205. package/src/components/ScheduleCalendar.vue +82 -7
  206. package/src/components/ScientificNumber.vue +0 -4
  207. package/src/components/SectionCard.vue +0 -4
  208. package/src/components/SegmentedControl.vue +48 -5
  209. package/src/components/SequenceInput.vue +0 -4
  210. package/src/components/SequenceProgressBar.story.vue +110 -0
  211. package/src/components/SequenceProgressBar.vue +0 -4
  212. package/src/components/SettingsModal.vue +0 -4
  213. package/src/components/Skeleton.vue +0 -4
  214. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  215. package/src/components/SmartGroupManual.vue +0 -4
  216. package/src/components/StatusIndicator.vue +0 -4
  217. package/src/components/StepWizard.vue +0 -4
  218. package/src/components/TagsInput.vue +4 -6
  219. package/src/components/ThemeToggle.vue +0 -4
  220. package/src/components/TimePicker.vue +36 -7
  221. package/src/components/TimeRangeInput.vue +0 -4
  222. package/src/components/Tooltip.story.vue +3 -3
  223. package/src/components/Tooltip.vue +0 -4
  224. package/src/components/UnitInput.vue +0 -4
  225. package/src/components/WellPlate.geometry.ts +60 -1
  226. package/src/components/WellPlate.interaction.ts +44 -0
  227. package/src/components/WellPlate.story.vue +8 -0
  228. package/src/components/WellPlate.vue +53 -7
  229. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  230. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  231. package/src/components/internal/DataStateInternal.vue +74 -0
  232. package/src/components/internal/FormSectionRenderer.vue +0 -4
  233. package/src/components/internal/WellEditPopupInternal.vue +0 -4
  234. package/src/composables/controlSchemaTypes.ts +34 -0
  235. package/src/composables/index.ts +10 -0
  236. package/src/composables/useDropdownState.ts +35 -5
  237. package/src/composables/useEventStream.ts +14 -2
  238. package/src/composables/useFileImport.ts +2 -7
  239. package/src/composables/useGeneratedAnalysis.ts +8 -9
  240. package/src/composables/useListReorder.story.vue +143 -0
  241. package/src/composables/useListReorder.ts +242 -0
  242. package/src/composables/useMenuKeyboard.ts +2 -2
  243. package/src/composables/useOptimisticMutation.ts +1 -15
  244. package/src/composables/usePluginConfig.ts +3 -1
  245. package/src/composables/useRackEditor.ts +2 -11
  246. package/src/composables/useRequestSyncState.ts +98 -28
  247. package/src/composables/useResourceCrud.ts +1 -15
  248. package/src/composables/useScheduleDrag.ts +37 -0
  249. package/src/composables/useWellPainting.ts +5 -29
  250. package/src/composables/useWellPlateEditor.ts +1 -11
  251. package/src/permissions.ts +48 -9
  252. package/src/stores/experiment.ts +2 -7
  253. package/src/stores/index.ts +9 -1
  254. package/src/stores/settings.ts +93 -1
  255. package/src/styles/components/audit-trail.css +5 -5
  256. package/src/styles/components/batch-progress-list.css +7 -0
  257. package/src/styles/components/color-slider.css +2 -2
  258. package/src/styles/components/data-state.css +30 -0
  259. package/src/styles/components/dataframe.css +29 -35
  260. package/src/styles/components/experiment-data-viewer.css +4 -4
  261. package/src/styles/components/experiment-timeline.css +3 -30
  262. package/src/styles/components/form-builder.css +5 -5
  263. package/src/styles/components/lcms-sequence-table.css +16 -1
  264. package/src/styles/components/multi-select.css +1 -1
  265. package/src/styles/components/reagent-list.css +38 -31
  266. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  267. package/src/styles/components/sample-selector.css +9 -2
  268. package/src/styles/components/schedule-calendar.css +8 -0
  269. package/src/styles/components/scientific-number.css +1 -1
  270. package/src/styles/components/well-plate.css +8 -0
  271. package/src/styles/index.css +8 -0
  272. package/src/styles/variables.css +29 -0
  273. package/src/templates/builderPresetControls.ts +1 -1
  274. package/src/templates/componentPlateHelpers.ts +3 -1
  275. package/src/templates/doseResponseAdapters.ts +2 -13
  276. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  277. package/src/templates/plateMapBuilder.ts +2 -2
  278. package/src/templates/qpcrPlateBuilder.ts +1 -1
  279. package/src/templates/templateValidators.ts +1 -1
  280. package/src/templates/timeCourseBuilder.ts +2 -2
  281. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  282. package/src/utils/color.ts +51 -0
  283. package/src/utils/errors.ts +29 -0
  284. package/dist/EmptyState-NBqf2_8z.js.map +0 -1
  285. package/dist/ExperimentPopover-CfOdh5Rm.js.map +0 -1
  286. package/dist/ExperimentSelectorModal-DvIagrxY.js.map +0 -1
  287. package/dist/SettingsModal-W3TYfnP9.js.map +0 -1
  288. package/dist/components-B80gV0P6.js.map +0 -1
  289. package/dist/composables/autoGroupConstants.d.ts +0 -1
  290. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  291. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  292. package/dist/composables-C8mmD5ta.js.map +0 -1
  293. package/dist/experiment-Y9Iz7KYi.js.map +0 -1
  294. package/dist/templates/builderDefaults.d.ts +0 -1
  295. package/dist/templates/plateGeometry.d.ts +0 -4
  296. package/dist/templates-CK72aKO1.js.map +0 -1
  297. package/dist/useApi-CDBq6z23.js.map +0 -1
  298. package/dist/useControlSchema-_OVhavKq.js.map +0 -1
  299. package/dist/useDropdownState-D5G4UvWd.js.map +0 -1
  300. package/dist/useProtocolTemplates-Dq5Pzwyd.js.map +0 -1
  301. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  302. package/src/composables/autoGroupConstants.ts +0 -4
  303. package/src/composables/autoGroupGrouping.ts +0 -148
  304. package/src/composables/useAutoGroupInputSources.ts +0 -147
  305. package/src/templates/builderDefaults.ts +0 -11
  306. package/src/templates/plateGeometry.ts +0 -62
  307. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → components/DataStates.test.d.ts} +0 -0
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  /** Drag-and-drop two-zone assigner for splitting sample groups into control and treatment arms. */
3
- import { ref } from 'vue'
3
+ import { nextTick, ref, type ComponentPublicInstance } from 'vue'
4
4
  import type { GroupItem } from '../types'
5
5
  import { useGroupAssignment, type GroupAssignmentState, type GroupAssignmentZone } from '../composables/useGroupAssignment'
6
+ import { useReorderAnnouncer } from '../composables/useListReorder'
6
7
 
7
8
  interface Props {
8
9
  groups: GroupItem[]
@@ -98,6 +99,56 @@ function emitAssignment(state: GroupAssignmentState) {
98
99
  emit('update:group1', state.group1)
99
100
  emit('update:group2', state.group2)
100
101
  }
102
+
103
+ // Keyboard alternative to the pointer drag. GroupAssigner moves items between
104
+ // zones rather than reordering one list, so it shares the announcer (and the
105
+ // Alt+Arrow idiom) with useListReorder without its index maths.
106
+ const { announcement, announce, announcerStyle } = useReorderAnnouncer()
107
+ const pillRefs = new Map<string, HTMLElement>()
108
+
109
+ function setPillRef(name: string, el: Element | ComponentPublicInstance | null) {
110
+ if (el instanceof HTMLElement) {
111
+ pillRefs.set(name, el)
112
+ } else {
113
+ pillRefs.delete(name)
114
+ }
115
+ }
116
+
117
+ function zoneLabel(zone: GroupAssignmentZone | null): string {
118
+ if (zone === 'zone1') return props.label1
119
+ if (zone === 'zone2') return props.label2
120
+ return 'Available Groups'
121
+ }
122
+
123
+ /** Alt+Left / Alt+Right walk a group through Control → unassigned → Treatment. */
124
+ function handlePillKeydown(event: KeyboardEvent, groupName: string) {
125
+ if (!event.altKey) return
126
+ const direction =
127
+ event.key === 'ArrowLeft' ? -1 : event.key === 'ArrowRight' ? 1 : 0
128
+ if (direction === 0) return
129
+
130
+ event.preventDefault()
131
+ const order: Array<GroupAssignmentZone | null> = ['zone1', null, 'zone2']
132
+ const current = order.indexOf(assignment.getZoneForGroup(groupName))
133
+ const next = order[current + direction]
134
+ if (current === -1 || next === undefined) return
135
+
136
+ if (next === null) {
137
+ const from = assignment.getZoneForGroup(groupName)
138
+ if (from) removeFromZone(groupName, from)
139
+ } else {
140
+ assignToZone(groupName, next)
141
+ }
142
+
143
+ announce(`${groupName} moved to ${zoneLabel(next)}.`)
144
+ void nextTick(() => pillRefs.get(groupName)?.focus())
145
+ }
146
+
147
+ /** Instructions read out with each pill. */
148
+ function pillLabel(group: GroupItem): string {
149
+ const zone = assignment.getZoneForGroup(group.name)
150
+ return `${group.name}, ${zoneLabel(zone)}. Press Alt with the left or right arrow keys to move it.`
151
+ }
101
152
  </script>
102
153
 
103
154
  <template>
@@ -125,10 +176,14 @@ function emitAssignment(state: GroupAssignmentState) {
125
176
  <div
126
177
  v-for="group in zone1Groups"
127
178
  :key="group.name"
179
+ :ref="(el) => setPillRef(group.name, el)"
128
180
  class="mint-group-assigner__pill"
129
181
  draggable="true"
182
+ tabindex="0"
183
+ :aria-label="pillLabel(group)"
130
184
  @dragstart="handleDragStart($event, group.name)"
131
185
  @dragend="handleDragEnd"
186
+ @keydown="handlePillKeydown($event, group.name)"
132
187
  >
133
188
  <span
134
189
  class="mint-group-assigner__pill-color"
@@ -174,10 +229,14 @@ function emitAssignment(state: GroupAssignmentState) {
174
229
  <div
175
230
  v-for="group in zone2Groups"
176
231
  :key="group.name"
232
+ :ref="(el) => setPillRef(group.name, el)"
177
233
  class="mint-group-assigner__pill"
178
234
  draggable="true"
235
+ tabindex="0"
236
+ :aria-label="pillLabel(group)"
179
237
  @dragstart="handleDragStart($event, group.name)"
180
238
  @dragend="handleDragEnd"
239
+ @keydown="handlePillKeydown($event, group.name)"
181
240
  >
182
241
  <span
183
242
  class="mint-group-assigner__pill-color"
@@ -221,14 +280,18 @@ function emitAssignment(state: GroupAssignmentState) {
221
280
  <div
222
281
  v-for="group in unassignedGroups"
223
282
  :key="group.name"
283
+ :ref="(el) => setPillRef(group.name, el)"
224
284
  :class="[
225
285
  'mint-group-assigner__pill',
226
286
  'mint-group-assigner__pill--unassigned',
227
287
  draggingGroup === group.name ? 'mint-group-assigner__pill--dragging' : '',
228
288
  ]"
229
289
  draggable="true"
290
+ tabindex="0"
291
+ :aria-label="pillLabel(group)"
230
292
  @dragstart="handleDragStart($event, group.name)"
231
293
  @dragend="handleDragEnd"
294
+ @keydown="handlePillKeydown($event, group.name)"
232
295
  >
233
296
  <span
234
297
  class="mint-group-assigner__pill-color"
@@ -240,6 +303,9 @@ function emitAssignment(state: GroupAssignmentState) {
240
303
  </div>
241
304
  </div>
242
305
 
306
+ <!-- Assignment announcements for screen readers -->
307
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ announcement }}</div>
308
+
243
309
  <!-- Validation message -->
244
310
  <div v-if="validationMessage" class="mint-group-assigner__validation">
245
311
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -251,7 +317,3 @@ function emitAssignment(state: GroupAssignmentState) {
251
317
  </div>
252
318
  </div>
253
319
  </template>
254
-
255
- <style>
256
- @import '../styles/components/group-assigner.css';
257
- </style>
@@ -67,7 +67,3 @@ function handleClick(event: MouseEvent) {
67
67
  </span>
68
68
  </button>
69
69
  </template>
70
-
71
- <style>
72
- @import '../styles/components/icon-button.css';
73
- </style>
@@ -185,7 +185,3 @@ function alertDetail(alert: InstrumentAlert): string {
185
185
  </TransitionGroup>
186
186
  </div>
187
187
  </template>
188
-
189
- <style>
190
- @import '../styles/components/instrument-monitor.css';
191
- </style>
@@ -44,7 +44,3 @@ const shouldPulse = computed(() => props.pulseWhenRunning && normalizedState.val
44
44
  {{ label ?? config.label }}
45
45
  </span>
46
46
  </template>
47
-
48
- <style>
49
- @import '../styles/components/instrument-monitor.css';
50
- </style>
@@ -182,7 +182,3 @@ function hasRemaining(progress: SequenceProgress | null | undefined): boolean {
182
182
  </template>
183
183
  </div>
184
184
  </template>
185
-
186
- <style>
187
- @import '../styles/components/instrument-monitor.css';
188
- </style>
@@ -401,7 +401,3 @@ async function clearFinished(): Promise<void> {
401
401
  </div>
402
402
  </Teleport>
403
403
  </template>
404
-
405
- <style>
406
- @import '../styles/components/jobs-status-tray.css';
407
- </style>
@@ -1,12 +1,14 @@
1
1
  <script setup lang="ts">
2
2
  /** Table for Xcalibur-compatible LCMS sequence rows with optional reorder/remove/duplicate controls. */
3
- import { computed, ref } from 'vue'
3
+ import { computed, type ComponentPublicInstance } from 'vue'
4
+ import { useListReorder } from '../composables/useListReorder'
4
5
  import {
5
6
  basenameFromWindowsPath,
6
7
  DEFAULT_LCMS_SEQUENCE_COLUMNS,
7
8
  type LcmsSequenceItem,
8
9
  type LcmsSequenceTableColumn,
9
10
  } from '../lcms'
11
+ import DataStateInternal from './internal/DataStateInternal.vue'
10
12
 
11
13
  interface Props {
12
14
  items?: LcmsSequenceItem[]
@@ -15,6 +17,13 @@ interface Props {
15
17
  maxRows?: number
16
18
  showMoreLabel?: boolean
17
19
  emptyMessage?: string
20
+ /** Replace the table with a loading placeholder. */
21
+ loading?: boolean
22
+ /**
23
+ * Error message. When set, the table is replaced by an error state.
24
+ * `null`/`undefined` renders normally.
25
+ */
26
+ error?: string | null
18
27
  }
19
28
 
20
29
  const props = withDefaults(defineProps<Props>(), {
@@ -24,6 +33,8 @@ const props = withDefaults(defineProps<Props>(), {
24
33
  maxRows: undefined,
25
34
  showMoreLabel: true,
26
35
  emptyMessage: 'No sequence items to display',
36
+ loading: false,
37
+ error: null,
27
38
  })
28
39
 
29
40
  const emit = defineEmits<{
@@ -32,8 +43,38 @@ const emit = defineEmits<{
32
43
  duplicate: [index: number]
33
44
  }>()
34
45
 
35
- const dragIndex = ref<number | null>(null)
36
- const dropTargetIndex = ref<number | null>(null)
46
+ // Rows are a plain ordered list: pointer drag plus an Alt+Arrow keyboard
47
+ // alternative, both from the shared reorder composable.
48
+ const handleRefs = new Map<string, HTMLElement>()
49
+
50
+ const {
51
+ draggingId,
52
+ dragOverId,
53
+ announcement: reorderAnnouncement,
54
+ announcerStyle,
55
+ onDragStart,
56
+ onDragOver,
57
+ onDragLeave,
58
+ onDrop,
59
+ onDragEnd,
60
+ onKeydown: onReorderKeydown,
61
+ } = useListReorder<LcmsSequenceItem>({
62
+ items: () => props.items,
63
+ getId: (_item, index) => String(index),
64
+ getLabel: (item) => item.file_name,
65
+ disabled: () => !props.editable,
66
+ getElement: (id) => handleRefs.get(id),
67
+ itemNoun: 'Row',
68
+ onReorder: ({ fromIndex, toIndex }) => emit('reorder', fromIndex, toIndex),
69
+ })
70
+
71
+ function setHandleRef(index: number, el: Element | ComponentPublicInstance | null) {
72
+ if (el instanceof HTMLElement) {
73
+ handleRefs.set(String(index), el)
74
+ } else {
75
+ handleRefs.delete(String(index))
76
+ }
77
+ }
37
78
 
38
79
  const displayItems = computed(() => {
39
80
  if (!props.maxRows) return props.items
@@ -60,42 +101,11 @@ function cellValue(item: LcmsSequenceItem, column: LcmsSequenceTableColumn, inde
60
101
  return item[column.key] ?? ''
61
102
  }
62
103
 
63
- function onDragStart(event: DragEvent, index: number) {
64
- if (!props.editable) return
65
- dragIndex.value = index
66
- if (event.dataTransfer) {
67
- event.dataTransfer.effectAllowed = 'move'
68
- event.dataTransfer.setData('text/plain', String(index))
69
- }
70
- }
71
-
72
- function onDragOver(event: DragEvent, index: number) {
73
- if (!props.editable) return
74
- event.preventDefault()
75
- if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'
76
- if (dragIndex.value !== null && dragIndex.value !== index) {
77
- dropTargetIndex.value = index
78
- }
79
- }
80
-
81
- function clearDragState() {
82
- dragIndex.value = null
83
- dropTargetIndex.value = null
84
- }
85
-
86
- function onDrop(event: DragEvent, toIndex: number) {
87
- if (!props.editable) return
88
- event.preventDefault()
89
- if (dragIndex.value !== null && dragIndex.value !== toIndex) {
90
- emit('reorder', dragIndex.value, toIndex)
91
- }
92
- clearDragState()
93
- }
94
104
  </script>
95
105
 
96
106
  <template>
97
107
  <div class="mint-lcms-sequence-table">
98
- <div class="mint-lcms-sequence-table__scroller">
108
+ <div v-if="!loading && !error && items.length > 0" class="mint-lcms-sequence-table__scroller">
99
109
  <table class="mint-lcms-sequence-table__table">
100
110
  <thead>
101
111
  <tr>
@@ -120,19 +130,27 @@ function onDrop(event: DragEvent, toIndex: number) {
120
130
  :draggable="editable"
121
131
  class="mint-lcms-sequence-table__row"
122
132
  :class="{
123
- 'mint-lcms-sequence-table__row--dragging': dragIndex === index,
124
- 'mint-lcms-sequence-table__row--drop-above': dropTargetIndex === index && dragIndex !== null && dragIndex > index,
125
- 'mint-lcms-sequence-table__row--drop-below': dropTargetIndex === index && dragIndex !== null && dragIndex < index,
133
+ 'mint-lcms-sequence-table__row--dragging': draggingId === String(index),
134
+ 'mint-lcms-sequence-table__row--drop-above': dragOverId === String(index) && draggingId !== null && Number(draggingId) > index,
135
+ 'mint-lcms-sequence-table__row--drop-below': dragOverId === String(index) && draggingId !== null && Number(draggingId) < index,
126
136
  }"
127
- @dragstart="onDragStart($event, index)"
137
+ @dragstart="onDragStart($event, item, index)"
128
138
  @dragenter.prevent
129
- @dragover="onDragOver($event, index)"
130
- @dragleave="dropTargetIndex = null"
131
- @drop="onDrop($event, index)"
132
- @dragend="clearDragState"
139
+ @dragover="onDragOver($event, item, index)"
140
+ @dragleave="onDragLeave"
141
+ @drop="onDrop($event, item, index)"
142
+ @dragend="onDragEnd"
133
143
  >
134
144
  <td v-if="editable" class="mint-lcms-sequence-table__drag-cell">
135
- <span class="mint-lcms-sequence-table__drag-handle" aria-hidden="true">::</span>
145
+ <button
146
+ :ref="(el) => setHandleRef(index, el)"
147
+ type="button"
148
+ class="mint-lcms-sequence-table__drag-handle"
149
+ :aria-label="`Reorder ${item.file_name}. Press Alt with the arrow keys to move it.`"
150
+ @keydown="onReorderKeydown($event, item, index)"
151
+ >
152
+ ::
153
+ </button>
136
154
  </td>
137
155
  <td
138
156
  v-for="column in columns"
@@ -176,16 +194,29 @@ function onDrop(event: DragEvent, toIndex: number) {
176
194
  </table>
177
195
  </div>
178
196
 
179
- <div v-if="items.length === 0" class="mint-lcms-sequence-table__empty">
180
- {{ emptyMessage }}
197
+ <div v-else-if="error" class="mint-lcms-sequence-table__state">
198
+ <slot name="error" :error="error">
199
+ <DataStateInternal state="error" size="sm" :title="error" />
200
+ </slot>
201
+ </div>
202
+
203
+ <div v-else-if="loading" class="mint-lcms-sequence-table__state">
204
+ <slot name="loading">
205
+ <DataStateInternal state="loading" size="sm" loading-label="Loading sequence" />
206
+ </slot>
207
+ </div>
208
+
209
+ <div v-else class="mint-lcms-sequence-table__state">
210
+ <slot name="empty">
211
+ <DataStateInternal state="empty" size="sm" :title="emptyMessage" />
212
+ </slot>
181
213
  </div>
182
214
 
183
215
  <div v-if="hasMore && showMoreLabel" class="mint-lcms-sequence-table__more">
184
216
  Showing first {{ maxRows }} of {{ items.length }} items
185
217
  </div>
218
+
219
+ <!-- Reorder announcements for screen readers -->
220
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ reorderAnnouncement }}</div>
186
221
  </div>
187
222
  </template>
188
-
189
- <style>
190
- @import '../styles/components/lcms-sequence-table.css';
191
- </style>
@@ -44,7 +44,3 @@ withDefaults(defineProps<Props>(), {
44
44
  <span class="mint-spinner__label">{{ label }}</span>
45
45
  </div>
46
46
  </template>
47
-
48
- <style>
49
- @import '../styles/components/loading-spinner.css';
50
- </style>
@@ -109,7 +109,3 @@ const {
109
109
  :is-supported="isSupported"
110
110
  />
111
111
  </template>
112
-
113
- <style>
114
- @import '../styles/components/mobile-support-gate.css';
115
- </style>
@@ -420,7 +420,3 @@ onUnmounted(() => {
420
420
  </div>
421
421
  </div>
422
422
  </template>
423
-
424
- <style>
425
- @import '../styles/components/molecule-input.css';
426
- </style>
@@ -117,7 +117,3 @@ const selectedLabels = computed(() => {
117
117
  </div>
118
118
  </div>
119
119
  </template>
120
-
121
- <style>
122
- @import '../styles/components/multi-select.css';
123
- </style>
@@ -156,7 +156,3 @@ function increment() {
156
156
  />
157
157
  </div>
158
158
  </template>
159
-
160
- <style>
161
- @import '../styles/components/number-input.css';
162
- </style>
@@ -1,22 +1,15 @@
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, PlateMap } from '../types'
4
+ import type { PlateMapEditorState, WellPlateFormat, SampleType, Well, PlateMap, SlotPosition } from '../types'
5
+ // Slot colors matching MSExpDesigner — shared with RackEditor.
6
+ import { SLOT_COLORS, SLOT_ORDER } from '../utils/color'
5
7
  import { useWellPlateEditor } from '../composables/useWellPlateEditor'
6
8
  import { useEventListener } from '../composables/useEventListener'
7
9
  import WellPlate from './WellPlate.vue'
8
10
  import SampleLegend from './SampleLegend.vue'
9
11
  import PlateMapEditorToolbarInternal from './internal/PlateMapEditorToolbarInternal.vue'
10
12
 
11
- // Slot colors matching MSExpDesigner
12
- type SlotPosition = 'R' | 'G' | 'B' | 'Y'
13
- const SLOT_COLORS: Record<SlotPosition, string> = {
14
- R: '#ef4444', // red
15
- G: '#22c55e', // green
16
- B: '#3b82f6', // blue
17
- Y: '#eab308', // yellow
18
- }
19
- const SLOT_ORDER: SlotPosition[] = ['R', 'G', 'B', 'Y']
20
13
 
21
14
  interface Props {
22
15
  modelValue?: PlateMapEditorState
@@ -428,7 +421,3 @@ useEventListener(() => document, 'keydown', handleKeyDown)
428
421
  </Teleport>
429
422
  </div>
430
423
  </template>
431
-
432
- <style>
433
- @import '../styles/components/plate-map-editor.css';
434
- </style>
@@ -152,7 +152,3 @@ const rootStyle = computed(() =>
152
152
  />
153
153
  </span>
154
154
  </template>
155
-
156
- <style>
157
- @import '../styles/components/plugin-icon.css';
158
- </style>
@@ -111,7 +111,3 @@ const segmentCount = computed(() => props.steps.length || 0)
111
111
  </div>
112
112
  </div>
113
113
  </template>
114
-
115
- <style>
116
- @import '../styles/components/progress-bar.css';
117
- </style>
@@ -53,6 +53,7 @@ const selectedTemplateId = ref<string | null>(null)
53
53
  const {
54
54
  isOpen: templateDropdownOpen,
55
55
  rootRef: templateDropdownRef,
56
+ triggerRef: templateTriggerRef,
56
57
  close: closeTemplateDropdown,
57
58
  toggle: toggleTemplateDropdown,
58
59
  } = useDropdownState()
@@ -204,6 +205,7 @@ watch(
204
205
  <label class="mint-protocol-editor__template-label">Template</label>
205
206
  <div ref="templateDropdownRef" class="mint-protocol-editor__template-dropdown">
206
207
  <button
208
+ ref="templateTriggerRef"
207
209
  type="button"
208
210
  class="mint-protocol-editor__template-btn"
209
211
  @click="toggleTemplateDropdown"
@@ -376,7 +378,3 @@ watch(
376
378
  </div>
377
379
  </div>
378
380
  </template>
379
-
380
- <style>
381
- @import '../styles/components/protocol-step-editor.css';
382
- </style>
@@ -1,7 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  /** Multi-rack editor for managing collections of well-plate racks with add/remove/reorder controls and per-well editing. */
3
- import { ref, computed, watch } from 'vue'
3
+ import { computed, watch, type ComponentPublicInstance } from 'vue'
4
+ import { SLOT_COLORS, SLOT_ORDER } from '../utils/color'
4
5
  import type { Rack, SlotPosition, WellPlateFormat, WellPlateSize, WellEditData, Well, WellEditField, WellSampleDropData, RackSampleDropMapper } from '../types'
6
+ import { useListReorder } from '../composables/useListReorder'
5
7
  import { useRackEditor } from '../composables/useRackEditor'
6
8
  import WellPlate from './WellPlate.vue'
7
9
 
@@ -104,23 +106,48 @@ watch(
104
106
  },
105
107
  )
106
108
 
107
- const SLOT_COLORS: Record<SlotPosition, string> = {
108
- R: '#ef4444',
109
- G: '#22c55e',
110
- B: '#3b82f6',
111
- Y: '#eab308',
112
- }
113
-
114
- const SLOT_OPTIONS: SlotPosition[] = ['R', 'G', 'B', 'Y']
109
+ const SLOT_OPTIONS: readonly SlotPosition[] = SLOT_ORDER
115
110
 
116
111
  const FORMAT_OPTIONS: { value: WellPlateFormat; label: string }[] = [
117
112
  { value: 54, label: '54' },
118
113
  { value: 96, label: '96' },
119
114
  ]
120
115
 
121
- // Drag state for rack reordering
122
- const draggingRackId = ref<string | null>(null)
123
- const dragOverRackId = ref<string | null>(null)
116
+ // Rack tab reordering: HTML5 drag for pointers, Alt+Arrow for the keyboard,
117
+ // both owned by the shared reorder composable.
118
+ const tabRefs = new Map<string, HTMLElement>()
119
+
120
+ const {
121
+ draggingId: draggingRackId,
122
+ dragOverId: dragOverRackId,
123
+ announcement: reorderAnnouncement,
124
+ announcerStyle,
125
+ onDragStart: onRackDragStart,
126
+ onDragOver: onRackDragOver,
127
+ onDragLeave: onRackDragLeave,
128
+ onDrop: onRackDrop,
129
+ onDragEnd: onRackDragEnd,
130
+ onKeydown: onRackReorderKeydown,
131
+ } = useListReorder<Rack>({
132
+ items: () => editor.racks.value,
133
+ getId: (rack) => rack.id,
134
+ getLabel: (rack) => rack.name,
135
+ disabled: () => !props.allowReorder || props.readonly,
136
+ getElement: (id) => tabRefs.get(id),
137
+ itemNoun: 'Rack',
138
+ onReorder: ({ fromIndex, toIndex }) => {
139
+ editor.reorderRacks(fromIndex, toIndex)
140
+ emit('rack-reorder', editor.racks.value.map(r => r.id))
141
+ },
142
+ })
143
+
144
+ function setTabRef(id: string, el: Element | ComponentPublicInstance | null) {
145
+ if (el instanceof HTMLElement) {
146
+ tabRefs.set(id, el)
147
+ } else {
148
+ tabRefs.delete(id)
149
+ }
150
+ }
124
151
 
125
152
  function handleAddRack() {
126
153
  const rack = editor.addRack()
@@ -136,54 +163,6 @@ function handleTabClick(rackId: string) {
136
163
  editor.setActiveRack(rackId)
137
164
  }
138
165
 
139
- // Rack drag handlers
140
- function handleRackDragStart(event: DragEvent, rackId: string) {
141
- if (!props.allowReorder) return
142
- draggingRackId.value = rackId
143
- if (event.dataTransfer) {
144
- event.dataTransfer.effectAllowed = 'move'
145
- event.dataTransfer.setData('text/plain', rackId)
146
- }
147
- }
148
-
149
- function handleRackDragOver(event: DragEvent, rackId: string) {
150
- event.preventDefault()
151
- if (draggingRackId.value && draggingRackId.value !== rackId) {
152
- dragOverRackId.value = rackId
153
- }
154
- }
155
-
156
- function handleRackDragLeave() {
157
- dragOverRackId.value = null
158
- }
159
-
160
- function handleRackDrop(event: DragEvent, targetRackId: string) {
161
- event.preventDefault()
162
- if (!draggingRackId.value || draggingRackId.value === targetRackId) {
163
- clearDragState()
164
- return
165
- }
166
-
167
- const fromIndex = editor.racks.value.findIndex(r => r.id === draggingRackId.value)
168
- const toIndex = editor.racks.value.findIndex(r => r.id === targetRackId)
169
-
170
- if (fromIndex !== -1 && toIndex !== -1) {
171
- editor.reorderRacks(fromIndex, toIndex)
172
- emit('rack-reorder', editor.racks.value.map(r => r.id))
173
- }
174
-
175
- clearDragState()
176
- }
177
-
178
- function handleRackDragEnd() {
179
- clearDragState()
180
- }
181
-
182
- function clearDragState() {
183
- draggingRackId.value = null
184
- dragOverRackId.value = null
185
- }
186
-
187
166
  // Toolbar actions
188
167
  function handleFormatChange(format: WellPlateFormat) {
189
168
  if (!editor.activeRack.value) return
@@ -281,9 +260,11 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
281
260
  <div class="mint-rack-editor__tabs">
282
261
  <div class="mint-rack-editor__tabs-inner">
283
262
  <button
284
- v-for="rack in editor.racks.value"
263
+ v-for="(rack, rackIndex) in editor.racks.value"
285
264
  :key="rack.id"
265
+ :ref="(el) => setTabRef(rack.id, el)"
286
266
  :draggable="allowReorder && !readonly"
267
+ :title="allowReorder && !readonly ? `${rack.name} — press Alt with the arrow keys to reorder` : undefined"
287
268
  :class="[
288
269
  'mint-rack-editor__tab',
289
270
  {
@@ -293,11 +274,12 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
293
274
  },
294
275
  ]"
295
276
  @click="handleTabClick(rack.id)"
296
- @dragstart="handleRackDragStart($event, rack.id)"
297
- @dragover="handleRackDragOver($event, rack.id)"
298
- @dragleave="handleRackDragLeave"
299
- @drop="handleRackDrop($event, rack.id)"
300
- @dragend="handleRackDragEnd"
277
+ @keydown="onRackReorderKeydown($event, rack, rackIndex)"
278
+ @dragstart="onRackDragStart($event, rack, rackIndex)"
279
+ @dragover="onRackDragOver($event, rack, rackIndex)"
280
+ @dragleave="onRackDragLeave"
281
+ @drop="onRackDrop($event, rack, rackIndex)"
282
+ @dragend="onRackDragEnd"
301
283
  >
302
284
  <span
303
285
  class="mint-rack-editor__slot-dot"
@@ -434,9 +416,8 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
434
416
  </template>
435
417
  </WellPlate>
436
418
  </div>
419
+
420
+ <!-- Reorder announcements for screen readers -->
421
+ <div role="status" aria-live="polite" :style="announcerStyle">{{ reorderAnnouncement }}</div>
437
422
  </div>
438
423
  </template>
439
-
440
- <style>
441
- @import '../styles/components/rack-editor.css';
442
- </style>
@@ -412,7 +412,3 @@ function formatLevel(value: number): string {
412
412
  </div>
413
413
  </div>
414
414
  </template>
415
-
416
- <style>
417
- @import '../styles/components/reagent-editor.css';
418
- </style>