@morscherlab/mint-sdk 1.4.0-beta.7 → 1.4.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 (257) hide show
  1. package/dist/{ActionMenu-CScINahU.js → AlertBox-B2Bgr3ei.js} +40 -209
  2. package/dist/AlertBox-B2Bgr3ei.js.map +1 -0
  3. package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-Dq9W1jE2.js} +160 -109
  4. package/dist/AppSidebar-Dq9W1jE2.js.map +1 -0
  5. package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-nbJj51is.js} +2 -2
  6. package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-nbJj51is.js.map} +1 -1
  7. package/dist/ExperimentPopover-5T1fAq2L.js +337 -0
  8. package/dist/ExperimentPopover-5T1fAq2L.js.map +1 -0
  9. package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-65peG4Up.js} +198 -181
  10. package/dist/ExperimentSelectorModal-65peG4Up.js.map +1 -0
  11. package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-BtnnjWzs.js} +2 -2
  12. package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-BtnnjWzs.js.map} +1 -1
  13. package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-483nyI6b.js} +9 -9
  14. package/dist/SettingsModal-483nyI6b.js.map +1 -0
  15. package/dist/components/AppSidebar.vue.d.ts +1 -1
  16. package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
  17. package/dist/components/AuditTrail.vue.d.ts +1 -1
  18. package/dist/components/BaseSelect.vue.d.ts +2 -2
  19. package/dist/components/ChartContainer.vue.d.ts +2 -0
  20. package/dist/components/DatePicker.vue.d.ts +1 -1
  21. package/dist/components/ExperimentPopover.vue.d.ts +18 -0
  22. package/dist/components/ExperimentSelectorModal.vue.d.ts +0 -4
  23. package/dist/components/FilePicker.vue.d.ts +1 -1
  24. package/dist/components/FileUploader.vue.d.ts +2 -2
  25. package/dist/components/PluginIcon.vue.d.ts +2 -2
  26. package/dist/components/SampleSelector.vue.d.ts +6 -6
  27. package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
  28. package/dist/components/StepWizard.vue.d.ts +3 -0
  29. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +1 -1
  30. package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
  31. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
  32. package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
  33. package/dist/composables/createClient.d.ts +2 -0
  34. package/dist/composables/index.d.ts +1 -0
  35. package/dist/composables/pluginIdentity.d.ts +24 -0
  36. package/dist/composables/useAppExperiment.d.ts +8 -0
  37. package/dist/composables/useCalendarGrid.d.ts +1 -1
  38. package/dist/composables/useExperimentSelector.d.ts +6 -2
  39. package/dist/composables/usePlatform.d.ts +1 -0
  40. package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-B8CTXagP.js} +2 -2
  41. package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-B8CTXagP.js.map} +1 -1
  42. package/dist/{data-C2PwI_dn.js → data-CgILxDLW.js} +178 -124
  43. package/dist/data-CgILxDLW.js.map +1 -0
  44. package/dist/data.js +8 -8
  45. package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-Cqp6qNrR.js} +3 -3
  46. package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-Cqp6qNrR.js.map} +1 -1
  47. package/dist/index.js +19 -19
  48. package/dist/{install-DAID6c2-.js → install-BtLWTk6H.js} +15 -14
  49. package/dist/{install-DAID6c2-.js.map → install-BtLWTk6H.js.map} +1 -1
  50. package/dist/install.js +1 -1
  51. package/dist/{lab-DLwRl_Ql.js → lab-MHzp-_J8.js} +128 -147
  52. package/dist/lab-MHzp-_J8.js.map +1 -0
  53. package/dist/lab.js +4 -3
  54. package/dist/{records-BzTcxekG.js → records-B6gpM_3e.js} +472 -274
  55. package/dist/records-B6gpM_3e.js.map +1 -0
  56. package/dist/{runtime-D6gVat6r.js → runtime-7vfl_bI3.js} +27 -31
  57. package/dist/runtime-7vfl_bI3.js.map +1 -0
  58. package/dist/runtime.js +6 -6
  59. package/dist/{shell-5ju97nOS.js → shell-Cs9OJMnm.js} +5 -5
  60. package/dist/{shell-5ju97nOS.js.map → shell-Cs9OJMnm.js.map} +1 -1
  61. package/dist/shell.js +5 -5
  62. package/dist/styles.css +1606 -1666
  63. package/dist/types/componentWorkflowTypes.d.ts +2 -0
  64. package/dist/types/generated/platformContext.d.ts +1 -0
  65. package/dist/types/generated-ui.d.ts +4 -0
  66. package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-8yWMu-7_.js} +60 -2
  67. package/dist/useDropdownState-8yWMu-7_.js.map +1 -0
  68. package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-DHnxKFAF.js} +3 -3
  69. package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-DHnxKFAF.js.map} +1 -1
  70. package/dist/{useListReorder-CcbEYxX-.js → useListReorder-BitdUhxn.js} +109 -277
  71. package/dist/useListReorder-BitdUhxn.js.map +1 -0
  72. package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-DiwCt77M.js} +71 -57
  73. package/dist/useRackEditor-DiwCt77M.js.map +1 -0
  74. package/dist/{useRealtime-PalKue84.js → useRealtime-C3iy9QkU.js} +7 -4
  75. package/dist/useRealtime-C3iy9QkU.js.map +1 -0
  76. package/dist/useRequest-D506eHi8.js +244 -0
  77. package/dist/useRequest-D506eHi8.js.map +1 -0
  78. package/dist/utils/time.d.ts +7 -0
  79. package/package.json +1 -1
  80. package/src/__tests__/components/AppTopBar.test.ts +51 -2
  81. package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
  82. package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
  83. package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
  84. package/src/__tests__/components/BaseSelect.test.ts +2 -1
  85. package/src/__tests__/components/BatchProgressList.test.ts +16 -0
  86. package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
  87. package/src/__tests__/components/ChartContainer.test.ts +11 -0
  88. package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
  89. package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
  90. package/src/__tests__/components/DatePicker.test.ts +21 -0
  91. package/src/__tests__/components/DatePicker.time.test.ts +2 -2
  92. package/src/__tests__/components/EmptyState.test.ts +1 -1
  93. package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
  94. package/src/__tests__/components/ExperimentSelectorModal.test.ts +119 -13
  95. package/src/__tests__/components/GeneratedPluginView.test.ts +22 -1
  96. package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
  97. package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
  98. package/src/__tests__/components/SampleSelector.test.ts +13 -8
  99. package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
  100. package/src/__tests__/components/StepWizard.test.ts +11 -0
  101. package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
  102. package/src/__tests__/components/deprecationTags.test.ts +1 -1
  103. package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
  104. package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
  105. package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
  106. package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
  107. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  108. package/src/__tests__/styles/cssTokens.test.ts +2 -2
  109. package/src/__tests__/styles/menusShellRefresh.test.ts +14 -10
  110. package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
  111. package/src/__tests__/utils/time.test.ts +18 -1
  112. package/src/components/AdductText.story.vue +7 -0
  113. package/src/components/AdductText.vue +1 -1
  114. package/src/components/AlertBox.story.vue +2 -2
  115. package/src/components/AlertBox.vue +18 -16
  116. package/src/components/AppSidebar.story.vue +0 -28
  117. package/src/components/AppTopBar.story.vue +47 -12
  118. package/src/components/AppTopBar.vue +118 -114
  119. package/src/components/ArtifactSaveDialog.story.vue +23 -0
  120. package/src/components/ArtifactSaveDialog.vue +102 -12
  121. package/src/components/AuditTrail.story.vue +2 -1
  122. package/src/components/AuditTrail.vue +2 -21
  123. package/src/components/Avatar.vue +10 -14
  124. package/src/components/BaseSelect.multiple.story.vue +13 -2
  125. package/src/components/BaseSelect.vue +4 -3
  126. package/src/components/BatchProgressList.vue +35 -25
  127. package/src/components/ChartContainer.story.vue +2 -1
  128. package/src/components/ChartContainer.vue +8 -6
  129. package/src/components/ConfirmDialog.story.vue +1 -1
  130. package/src/components/EmptyState.vue +1 -1
  131. package/src/components/ExperimentPopover.story.vue +165 -53
  132. package/src/components/ExperimentPopover.vue +169 -187
  133. package/src/components/ExperimentSelectorModal.story.vue +40 -36
  134. package/src/components/ExperimentSelectorModal.vue +124 -110
  135. package/src/components/FormField.story.vue +8 -48
  136. package/src/components/GeneratedPluginView.vue +7 -1
  137. package/src/components/InstrumentStateBadge.vue +1 -1
  138. package/src/components/JobsStatusTray.vue +1 -1
  139. package/src/components/LoadingSpinner.vue +1 -1
  140. package/src/components/NumberInput.vue +3 -6
  141. package/src/components/PluginIcon.story.vue +2 -10
  142. package/src/components/PluginIcon.vue +2 -2
  143. package/src/components/PluginWorkspaceView.story.vue +1 -1
  144. package/src/components/RuntimeUpdateNotice.vue +1 -1
  145. package/src/components/SampleSelector.story.vue +1 -1
  146. package/src/components/SampleSelector.vue +27 -37
  147. package/src/components/SampleSelectorGroupNode.vue +1 -1
  148. package/src/components/SectionCard.story.vue +2 -2
  149. package/src/components/SequenceProgressBar.story.vue +9 -0
  150. package/src/components/SequenceProgressBar.vue +6 -1
  151. package/src/components/SettingsModal.schema.ts +1 -1
  152. package/src/components/SettingsModal.vue +2 -2
  153. package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
  154. package/src/components/SmartGroupManual.story.vue +1 -1
  155. package/src/components/StepWizard.story.vue +33 -0
  156. package/src/components/StepWizard.vue +8 -1
  157. package/src/components/WellPlate.story.vue +3 -1
  158. package/src/components/WellPlate.vue +7 -0
  159. package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
  160. package/src/components/internal/DatePickerDateInternal.vue +16 -40
  161. package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
  162. package/src/components/internal/DatePickerTimeInternal.vue +5 -8
  163. package/src/components/internal/ResourcePickerListInternal.vue +45 -85
  164. package/src/components/internal/SelectMultipleInternal.vue +182 -65
  165. package/src/components/internal/SelectSearchableInternal.vue +2 -3
  166. package/src/composables/createClient.ts +2 -0
  167. package/src/composables/index.ts +1 -0
  168. package/src/composables/pluginIdentity.ts +31 -0
  169. package/src/composables/useAppExperiment.ts +20 -0
  170. package/src/composables/useCalendarGrid.ts +4 -3
  171. package/src/composables/useExperimentSelector.ts +77 -31
  172. package/src/styles/components/adduct-text.css +13 -5
  173. package/src/styles/components/alert-box.css +39 -58
  174. package/src/styles/components/app-layout.css +6 -5
  175. package/src/styles/components/app-page-selector.css +3 -1
  176. package/src/styles/components/app-pill-nav.css +11 -12
  177. package/src/styles/components/app-sidebar.css +9 -18
  178. package/src/styles/components/app-top-bar.css +57 -55
  179. package/src/styles/components/artifact-save-dialog.css +153 -2
  180. package/src/styles/components/audit-trail.css +16 -19
  181. package/src/styles/components/avatar.css +6 -4
  182. package/src/styles/components/batch-progress-list.css +38 -36
  183. package/src/styles/components/button.css +28 -59
  184. package/src/styles/components/calendar.css +12 -12
  185. package/src/styles/components/chart-container.css +34 -23
  186. package/src/styles/components/checkbox.css +2 -12
  187. package/src/styles/components/collapsible-card.css +27 -29
  188. package/src/styles/components/confirm-dialog.css +13 -14
  189. package/src/styles/components/dataframe.css +12 -4
  190. package/src/styles/components/date-picker.css +80 -92
  191. package/src/styles/components/datetime-picker.css +31 -43
  192. package/src/styles/components/divider.css +20 -20
  193. package/src/styles/components/dose-calculator.css +3 -3
  194. package/src/styles/components/empty-state.css +20 -17
  195. package/src/styles/components/experiment-code-badge.css +2 -0
  196. package/src/styles/components/experiment-popover.css +174 -329
  197. package/src/styles/components/experiment-selector-modal.css +75 -56
  198. package/src/styles/components/file-picker.css +3 -3
  199. package/src/styles/components/file-uploader.css +38 -49
  200. package/src/styles/components/form-builder.css +3 -3
  201. package/src/styles/components/formula-input.css +1 -1
  202. package/src/styles/components/icon-button.css +18 -24
  203. package/src/styles/components/input.css +5 -4
  204. package/src/styles/components/instrument-monitor.css +13 -15
  205. package/src/styles/components/jobs-status-tray.css +31 -25
  206. package/src/styles/components/modal.css +2 -4
  207. package/src/styles/components/molecule-input.css +2 -2
  208. package/src/styles/components/multi-select.css +65 -117
  209. package/src/styles/components/number-input.css +26 -19
  210. package/src/styles/components/pill.css +3 -2
  211. package/src/styles/components/plate-editor.css +0 -1
  212. package/src/styles/components/plugin-icon.css +26 -23
  213. package/src/styles/components/popover.css +2 -2
  214. package/src/styles/components/presence-avatars.css +1 -1
  215. package/src/styles/components/protocol-step-editor.css +1 -3
  216. package/src/styles/components/resource-card.css +2 -2
  217. package/src/styles/components/resource-picker-list.css +6 -57
  218. package/src/styles/components/sample-hierarchy-tree.css +4 -4
  219. package/src/styles/components/sample-selector.css +95 -79
  220. package/src/styles/components/schedule-calendar.css +8 -8
  221. package/src/styles/components/searchable-select.css +12 -12
  222. package/src/styles/components/section-card.css +28 -47
  223. package/src/styles/components/segmented-control.css +18 -15
  224. package/src/styles/components/select.css +3 -3
  225. package/src/styles/components/sequence-input.css +2 -2
  226. package/src/styles/components/sequence-progress-bar.css +17 -8
  227. package/src/styles/components/smart-group.css +18 -18
  228. package/src/styles/components/step-wizard.css +52 -16
  229. package/src/styles/components/tabs.css +2 -2
  230. package/src/styles/components/textarea.css +3 -3
  231. package/src/styles/components/time-picker.css +36 -21
  232. package/src/styles/components/toast.css +12 -10
  233. package/src/styles/components/toggle.css +1 -11
  234. package/src/styles/components/tooltip.css +10 -9
  235. package/src/styles/components/unit-input.css +8 -7
  236. package/src/styles/components/well-plate.css +9 -2
  237. package/src/styles/variables.css +106 -75
  238. package/src/types/componentWorkflowTypes.ts +2 -0
  239. package/src/types/generated/platformContext.ts +1 -0
  240. package/src/types/generated-ui.ts +4 -0
  241. package/src/utils/time.ts +21 -0
  242. package/dist/ActionMenu-CScINahU.js.map +0 -1
  243. package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
  244. package/dist/BaseModal-DfRIuVoj.js.map +0 -1
  245. package/dist/ExperimentPopover-C4sGw-is.js +0 -359
  246. package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
  247. package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
  248. package/dist/SettingsModal-CSLE31yg.js.map +0 -1
  249. package/dist/data-C2PwI_dn.js.map +0 -1
  250. package/dist/lab-DLwRl_Ql.js.map +0 -1
  251. package/dist/records-BzTcxekG.js.map +0 -1
  252. package/dist/runtime-D6gVat6r.js.map +0 -1
  253. package/dist/useListReorder-CcbEYxX-.js.map +0 -1
  254. package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
  255. package/dist/useRealtime-PalKue84.js.map +0 -1
  256. package/dist/useRequest-D5JDfsgZ.js +0 -76
  257. package/dist/useRequest-D5JDfsgZ.js.map +0 -1
@@ -29,11 +29,11 @@ describe('SDK control refresh base-control rules', () => {
29
29
  })
30
30
 
31
31
  it('should find no soft or plain focus ring when scanning pressable controls (1a)', () => {
32
- const pressables = ['checkbox.css', 'radio-group.css', 'toggle.css', 'icon-button.css', 'multi-select.css']
32
+ const pressables = ['checkbox.css', 'radio-group.css', 'toggle.css', 'icon-button.css']
33
33
  expect(offenders(pressables, (l) => /var\(--focus-ring(-soft)?\)/.test(l))).toEqual([])
34
34
  })
35
35
 
36
- it.each(['input.css', 'select.css', 'textarea.css'])(
36
+ it.each(['input.css', 'select.css', 'textarea.css', 'multi-select.css'])(
37
37
  'should use the shared field hover border when scanning %s (1e)',
38
38
  (file) => {
39
39
  expect(css(file)).toContain('border-color: var(--_field-border-hover)')
@@ -77,6 +77,10 @@ describe('SDK control refresh base-control rules', () => {
77
77
  expect(offenders(['alert-box.css'], (l) => /\.mint-alert--\w+ \.mint-alert__title/.test(l))).toEqual([])
78
78
  })
79
79
 
80
+ it('should find no tone fill on the alert surface when scanning alert-box.css (v2 callout)', () => {
81
+ expect(offenders(['alert-box.css'], (l) => /^\.mint-alert--\w+\s*\{/.test(l))).toEqual([])
82
+ })
83
+
80
84
  it('should find no pill radius on the chip when scanning multi-select.css (1i)', () => {
81
85
  expect(offenders(['multi-select.css'], (l) => /9999px|999px/.test(l))).toEqual([])
82
86
  })
@@ -197,12 +197,6 @@ describe('SDK control refresh style rules', () => {
197
197
  expect(rule).toMatch(/padding:\s*0/)
198
198
  })
199
199
 
200
- it('should pad resource picker group bars to the modal gutter when scanning resource-picker-list.css', () => {
201
- const css = stripComments(readFileSync(component('resource-picker-list.css'), 'utf-8'))
202
- const rule = /\.mint-resource-picker__group\s*\{([^}]*)\}/.exec(css)?.[1] ?? ''
203
- expect(rule).toMatch(/padding:\s*0 1\.25rem/)
204
- })
205
-
206
200
  // The list sat in a bordered card inside the modal card.
207
201
  it('should draw no frame around the resource picker list when scanning resource-picker-list.css', () => {
208
202
  const css = stripComments(readFileSync(component('resource-picker-list.css'), 'utf-8'))
@@ -93,8 +93,8 @@ describe('CSS custom properties', () => {
93
93
 
94
94
  // 9a: PlotlyChart reads it through getComputedStyle('--font-sans'), which the
95
95
  // scan above counts as a declaration, so it slipped through as undefined.
96
- it('should declare --font-sans as Fira Sans when charts read the sans font token (9a)', () => {
97
- expect(variablesCss).toMatch(/--font-sans:\s*'Fira Sans'/)
96
+ it('should declare --font-sans as Geist when charts read the sans font token (9a)', () => {
97
+ expect(variablesCss).toMatch(/--font-sans:\s*'Geist'/)
98
98
  })
99
99
 
100
100
  it('does not use the platform-only --color-bg-*/--color-text-*/--color-border aliases', () => {
@@ -25,9 +25,9 @@ describe('menus and app shell styles', () => {
25
25
  expect(css('app-top-bar.css')).toMatch(/\.mint-topbar\s*\{[^}]*padding:\s*0\.75rem 1rem;/)
26
26
  })
27
27
 
28
- // 28px items + 3px track padding + 1px border on each side = the 36px top-bar control height.
29
- it('should size pill nav items so the track matches the 36px top-bar controls', () => {
30
- expect(css('app-pill-nav.css')).toMatch(/\.mint-pill-nav__item\s*\{[^}]*height:\s*1\.75rem;/)
28
+ // 26px items + 2px track padding + 1px border on each side = the 32px top-bar control height.
29
+ it('should size pill nav items so the track matches the 32px top-bar controls', () => {
30
+ expect(css('app-pill-nav.css')).toMatch(/\.mint-pill-nav__item\s*\{[^}]*height:\s*1\.625rem;/)
31
31
  })
32
32
 
33
33
  it('should size the page selector trigger to the 36px identity tile', () => {
@@ -44,17 +44,21 @@ describe('menus and app shell styles', () => {
44
44
  expect(css('app-top-bar.css')).toMatch(/\.mint-topbar__identity > \*\s*\{[^}]*max-width:\s*100%;[^}]*max-height:\s*100%;/)
45
45
  })
46
46
 
47
- // 15px x 1.15 + 12px x 1.2 = 31.7px, so the title group fits the 32px control row.
48
- it('should fit the top-bar title and subtitle inside the control row (5a)', () => {
49
- expect(css('app-top-bar.css')).toMatch(/\.mint-topbar-title\s*\{[^}]*line-height:\s*1\.15;/)
47
+ // 18px name + 15px subtitle lines, spread over the 36px identity tile height (top and bottom aligned).
48
+ it('should fit the top-bar title and subtitle to the 36px identity tile (5a)', () => {
49
+ const topBar = css('app-top-bar.css')
50
+ expect(topBar).toMatch(/\.mint-topbar-title-group\s*\{[^}]*justify-content:\s*space-between;[^}]*height:\s*2\.25rem;/)
51
+ expect(topBar).toMatch(/\.mint-topbar-title\s*\{[^}]*font-size:\s*0\.9375rem;[^}]*line-height:\s*1\.125rem;/)
52
+ expect(topBar).toMatch(/\.mint-topbar-subtitle\s*\{[^}]*font-size:\s*0\.75rem;[^}]*line-height:\s*0\.9375rem;/)
50
53
  })
51
54
 
52
- it('should size the top-bar experiment trigger to the 32px control height (5a)', () => {
53
- expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__trigger\s*\{[^}]*height:\s*var\(--form-height-sm\);/)
55
+ // Design v2: the joined [trigger | Save] group is 30px inside its 1px border.
56
+ it('should size the top-bar experiment trigger to the 30px v2 control height (5a)', () => {
57
+ expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__trigger\s*\{[^}]*height:\s*30px;/)
54
58
  })
55
59
 
56
- it('should size the top-bar experiment save trigger to the 32px control height (5a)', () => {
57
- expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__save-trigger\s*\{[^}]*height:\s*var\(--form-height-sm\);/)
60
+ it('should size the top-bar experiment save button to the 30px v2 control height (5a)', () => {
61
+ expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__save\s*\{[^}]*height:\s*30px;/)
58
62
  })
59
63
 
60
64
  it('should give settings number rows a 120px control (5d)', () => {
@@ -10,8 +10,8 @@ const tokens: Record<string, string> = {
10
10
  '--mint-sample-6': '#666666',
11
11
  '--mint-sample-7': '#777777',
12
12
  '--mint-sample-8': '#888888',
13
- '--font-sans': 'Fira Sans',
14
- '--font-mono': 'Fira Code',
13
+ '--font-sans': 'Geist',
14
+ '--font-mono': 'Geist Mono',
15
15
  '--text-primary': '#1E293B',
16
16
  '--text-secondary': '#64748B',
17
17
  '--border-light': '#F3F4F6',
@@ -35,11 +35,11 @@ describe('mintPlotlyTemplate', () => {
35
35
  })
36
36
 
37
37
  it('should set 12px sans body text in the primary text color when tokens are defined', () => {
38
- expect(mintPlotlyTemplate().layout?.font).toEqual({ family: 'Fira Sans', size: 12, color: '#1E293B' })
38
+ expect(mintPlotlyTemplate().layout?.font).toEqual({ family: 'Geist', size: 12, color: '#1E293B' })
39
39
  })
40
40
 
41
41
  it('should set 11px mono ticks in the secondary text color when tokens are defined', () => {
42
- expect(mintPlotlyTemplate().layout?.yaxis?.tickfont).toEqual({ family: 'Fira Code', size: 11, color: '#64748B' })
42
+ expect(mintPlotlyTemplate().layout?.yaxis?.tickfont).toEqual({ family: 'Geist Mono', size: 11, color: '#64748B' })
43
43
  })
44
44
 
45
45
  it('should draw the grid with --border-light when tokens are defined', () => {
@@ -1,6 +1,7 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
2
  import {
3
3
  findNearestTimeSlotIndex,
4
+ formatRelativeTime,
4
5
  formatTimeSlot,
5
6
  fromMinutes,
6
7
  generateTimeSlots,
@@ -25,4 +26,20 @@ describe('time', () => {
25
26
  expect(findNearestTimeSlotIndex('08:00', [])).toBe(-1)
26
27
  })
27
28
 
29
+ describe('formatRelativeTime', () => {
30
+ afterEach(() => {
31
+ vi.useRealTimers()
32
+ })
33
+
34
+ it.each([
35
+ [{ weeks: true }, '2 weeks ago'],
36
+ [{}, new Date('2026-10-14T12:00:00Z').toLocaleDateString()],
37
+ ])('should format a 14-day-old time as a week count only when weeks is on (%o)', (options, expected) => {
38
+ vi.useFakeTimers({ toFake: ['Date'] })
39
+ vi.setSystemTime(new Date('2026-10-28T12:00:00Z'))
40
+
41
+ expect(formatRelativeTime('2026-10-14T12:00:00Z', options)).toBe(expected)
42
+ })
43
+ })
44
+
28
45
  })
@@ -12,6 +12,13 @@ import AdductText from './AdductText.vue'
12
12
  </div>
13
13
  </Variant>
14
14
 
15
+ <Variant title="Badges">
16
+ <div style="display: flex; align-items: center; gap: 0.5rem; padding: 2rem;">
17
+ <AdductText v-for="v in ['[M+H]+', '[M-H]-', '[M+Na]+', '[M-H2O+H]+', '[M+2H]2+']" :key="v" :value="v" variant="badge" />
18
+ <AdductText value="[M+H]+" variant="badge" font="mono" />
19
+ </div>
20
+ </Variant>
21
+
15
22
  <Variant title="Tones and inherited size">
16
23
  <div style="display: flex; flex-direction: column; gap: 0.75rem; padding: 2rem; max-width: 600px; color: var(--text-primary); font-size: 0.875rem;">
17
24
  <div style="display: flex; align-items: center; gap: 1rem;">
@@ -17,7 +17,7 @@ const props = withDefaults(defineProps<Props>(), {
17
17
  variant: 'inline',
18
18
  tone: 'default',
19
19
  size: 'xs',
20
- font: 'mono',
20
+ font: 'sans',
21
21
  })
22
22
 
23
23
  const value = computed(() => props.value?.trim() ?? '')
@@ -35,7 +35,7 @@ function handleAction(label: string) {
35
35
  </AlertBox>
36
36
  <p
37
37
  v-if="actionFired"
38
- style="margin-top: 0.75rem; font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: 'Fira Code', monospace;"
38
+ style="margin-top: 0.75rem; font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: var(--font-mono);"
39
39
  >
40
40
  Action fired: "{{ actionFired }}"
41
41
  </p>
@@ -111,7 +111,7 @@ function handleAction(label: string) {
111
111
 
112
112
  <p
113
113
  v-if="actionFired"
114
- style="font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: 'Fira Code', monospace;"
114
+ style="font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: var(--font-mono);"
115
115
  >
116
116
  Action fired: "{{ actionFired }}"
117
117
  </p>
@@ -31,22 +31,24 @@ const hasActions = () => !!props.actionLabel || !!slots.actions
31
31
  :class="`mint-alert--${props.tone}`"
32
32
  role="alert"
33
33
  >
34
- <!-- Lucide circle-check -->
35
- <svg v-if="props.tone === 'success'" class="mint-alert__icon mint-alert__icon--success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
36
- <circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" />
37
- </svg>
38
- <!-- Lucide circle-x -->
39
- <svg v-else-if="props.tone === 'error'" class="mint-alert__icon mint-alert__icon--error" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
40
- <circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" />
41
- </svg>
42
- <!-- Lucide triangle-alert -->
43
- <svg v-else-if="props.tone === 'warning'" class="mint-alert__icon mint-alert__icon--warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
44
- <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /><path d="M12 9v4" /><path d="M12 17h.01" />
45
- </svg>
46
- <!-- Lucide info -->
47
- <svg v-else :class="['mint-alert__icon', `mint-alert__icon--${props.tone}`]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
48
- <circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" />
49
- </svg>
34
+ <span :class="['mint-alert__icon', `mint-alert__icon--${props.tone}`]">
35
+ <!-- Lucide circle-check -->
36
+ <svg v-if="props.tone === 'success'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
37
+ <circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" />
38
+ </svg>
39
+ <!-- Lucide circle-x -->
40
+ <svg v-else-if="props.tone === 'error'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
41
+ <circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" />
42
+ </svg>
43
+ <!-- Lucide triangle-alert -->
44
+ <svg v-else-if="props.tone === 'warning'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
45
+ <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /><path d="M12 9v4" /><path d="M12 17h.01" />
46
+ </svg>
47
+ <!-- Lucide info -->
48
+ <svg v-else viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
49
+ <circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" />
50
+ </svg>
51
+ </span>
50
52
 
51
53
  <div class="mint-alert__content">
52
54
  <h4 v-if="props.title" class="mint-alert__title">
@@ -36,16 +36,12 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
36
36
  label: 'Import Layout',
37
37
  subtitle: 'Upload from Excel',
38
38
  icon: icons.upload,
39
- iconColor: '#3b82f6',
40
- iconBg: '#dbeafe',
41
39
  },
42
40
  {
43
41
  id: 'naming',
44
42
  label: 'Experiment & Naming',
45
43
  subtitle: 'exp001_260210_XP_M...',
46
44
  icon: icons.fileText,
47
- iconColor: '#6366f1',
48
- iconBg: '#e0e7ff',
49
45
  showToggle: true,
50
46
  badge: 'on',
51
47
  badgeTone: 'success',
@@ -55,8 +51,6 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
55
51
  label: 'Randomize Samples',
56
52
  subtitle: 'Sequential order',
57
53
  icon: icons.shuffle,
58
- iconColor: '#6366f1',
59
- iconBg: '#e0e7ff',
60
54
  showToggle: true,
61
55
  badge: 3,
62
56
  badgeTone: 'cta',
@@ -70,16 +64,12 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
70
64
  label: 'Acquisition',
71
65
  subtitle: 'NEG, VIAL',
72
66
  icon: icons.zap,
73
- iconColor: '#ef4444',
74
- iconBg: '#fee2e2',
75
67
  },
76
68
  {
77
69
  id: 'method',
78
70
  label: 'Method & Path',
79
71
  subtitle: 'Select method',
80
72
  icon: icons.route,
81
- iconColor: '#8b5cf6',
82
- iconBg: '#ede9fe',
83
73
  defaultOpen: false,
84
74
  },
85
75
  ],
@@ -93,16 +83,12 @@ const simplePanels: Record<string, SidebarToolSection[]> = {
93
83
  label: 'Parameters',
94
84
  subtitle: 'Analysis settings',
95
85
  icon: ['M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z', 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z'],
96
- iconColor: '#6366f1',
97
- iconBg: '#e0e7ff',
98
86
  },
99
87
  {
100
88
  id: 'filters',
101
89
  label: 'Filters',
102
90
  subtitle: 'Refine results',
103
91
  icon: ['M22 3H2l8 9.46V19l4 2v-8.54L22 3'],
104
- iconColor: '#0ea5e9',
105
- iconBg: '#e0f2fe',
106
92
  defaultOpen: false,
107
93
  },
108
94
  ],
@@ -112,16 +98,12 @@ const simplePanels: Record<string, SidebarToolSection[]> = {
112
98
  label: 'Display Options',
113
99
  subtitle: 'Chart and table settings',
114
100
  icon: ['M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z', 'M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'],
115
- iconColor: '#8b5cf6',
116
- iconBg: '#ede9fe',
117
101
  },
118
102
  {
119
103
  id: 'export',
120
104
  label: 'Export',
121
105
  subtitle: 'Download data',
122
106
  icon: ['M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4', 'M7 10l5 5 5-5', 'M12 15V3'],
123
- iconColor: '#10b981',
124
- iconBg: '#d1fae5',
125
107
  defaultOpen: false,
126
108
  },
127
109
  ],
@@ -163,8 +145,6 @@ const schemaControls = defineControls({
163
145
  view: 'analysis',
164
146
  sidebar: {
165
147
  icon: icons.settings,
166
- iconColor: '#6366f1',
167
- iconBg: '#e0e7ff',
168
148
  },
169
149
  },
170
150
  method: {
@@ -180,16 +160,12 @@ const schemaControls = defineControls({
180
160
  default: true,
181
161
  hint: 'Keep flagged points visible',
182
162
  icon: icons.eye,
183
- iconColor: '#0ea5e9',
184
- iconBg: '#e0f2fe',
185
163
  section: 'display',
186
164
  sectionLabel: 'Display',
187
165
  sectionSubtitle: 'Result filters',
188
166
  view: 'analysis',
189
167
  sidebar: {
190
168
  icon: icons.zap,
191
- iconColor: '#0ea5e9',
192
- iconBg: '#e0f2fe',
193
169
  defaultOpen: false,
194
170
  },
195
171
  },
@@ -215,8 +191,6 @@ const modelDrivenSidebarModel = defineControlModel({
215
191
  description: 'Result cleanup',
216
192
  sidebar: {
217
193
  icon: icons.zap,
218
- iconColor: '#0ea5e9',
219
- iconBg: '#e0f2fe',
220
194
  defaultOpen: false,
221
195
  },
222
196
  controls: {
@@ -225,8 +199,6 @@ const modelDrivenSidebarModel = defineControlModel({
225
199
  default: true,
226
200
  hint: 'Keep flagged points visible',
227
201
  icon: icons.eye,
228
- iconColor: '#0ea5e9',
229
- iconBg: '#e0f2fe',
230
202
  },
231
203
  minPeakArea: { type: 'number', default: 1000, min: 0 },
232
204
  },
@@ -1,7 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import AppTopBar from './AppTopBar.vue'
3
3
  import Avatar from './Avatar.vue'
4
+ import PluginIcon from './PluginIcon.vue'
4
5
  import { ExperimentProvider } from '../__stories__/experiment-helpers'
6
+ import { providePluginIdentity } from '../composables/pluginIdentity'
7
+ import type { App } from 'vue'
5
8
  import type {
6
9
  TopBarVariant,
7
10
  PillNavItem,
@@ -59,6 +62,25 @@ const samplePlugin: PluginInfo = {
59
62
  settings_api: 'platform',
60
63
  }
61
64
 
65
+ const samplePluginWithSubtitle: PluginInfo = {
66
+ ...samplePlugin,
67
+ id: 'ms-planner',
68
+ name: 'ms-planner',
69
+ display_name: 'MS Planner',
70
+ subtitle: 'Experiment Scheduler',
71
+ icon: 'calendar',
72
+ route_prefix: '/ms-planner',
73
+ api_prefix: '/api/ms-planner',
74
+ }
75
+
76
+ // The seed is module state: clear it when the variant unmounts.
77
+ function seedIdentity({ app }: { app: App }) {
78
+ providePluginIdentity({
79
+ plugin: { name: 'ms-planner', displayName: 'MS Planner', subtitle: 'Experiment Scheduler', icon: 'calendar' },
80
+ })
81
+ app.onUnmount(() => providePluginIdentity({ plugin: { name: '' } }))
82
+ }
83
+
62
84
  </script>
63
85
 
64
86
  <template>
@@ -82,18 +104,7 @@ const samplePlugin: PluginInfo = {
82
104
  pill="experiments"
83
105
  >
84
106
  <template #icon>
85
- <div
86
- style="width: 2.25rem; height: 2.25rem; border-radius: 0.5rem; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #F97316 0%, #FB923C 100%);"
87
- >
88
- <svg
89
- style="width: 1.25rem; height: 1.25rem; color: white;"
90
- fill="none"
91
- stroke="currentColor"
92
- viewBox="0 0 24 24"
93
- >
94
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
95
- </svg>
96
- </div>
107
+ <PluginIcon size="topbar" />
97
108
  </template>
98
109
  </AppTopBar>
99
110
  </div>
@@ -223,6 +234,20 @@ const samplePlugin: PluginInfo = {
223
234
  </div>
224
235
  </Variant>
225
236
 
237
+ <Variant title="Identity · Integrated with subtitle">
238
+ <div style="padding: 2rem; background: var(--bg-primary); min-height: 12rem;">
239
+ <ExperimentProvider :plugin="samplePluginWithSubtitle">
240
+ <AppTopBar :spec="{ pills: samplePillNav, homePath: '' }" pill="workspace" />
241
+ </ExperimentProvider>
242
+ </div>
243
+ </Variant>
244
+
245
+ <Variant title="Identity · Standalone seeded" :setup-app="seedIdentity">
246
+ <div style="padding: 2rem;">
247
+ <AppTopBar :spec="{ pills: samplePillNav, homePath: '' }" pill="workspace" />
248
+ </div>
249
+ </Variant>
250
+
226
251
  <Variant title="Navigation · Page selector">
227
252
  <div style="padding: 2rem;">
228
253
  <AppTopBar
@@ -244,6 +269,16 @@ const samplePlugin: PluginInfo = {
244
269
  </div>
245
270
  </Variant>
246
271
 
272
+ <Variant title="Navigation · Pill nav overflow (More)">
273
+ <div style="padding: 2rem; min-height: 14rem;">
274
+ <AppTopBar
275
+ :spec="{ pills: ['Queue', 'Calendar', 'Utilization', 'Instruments', 'Reports', 'Settings', 'Logs'], homePath: '' }"
276
+ title="MS Planner"
277
+ pill="Reports"
278
+ />
279
+ </div>
280
+ </Variant>
281
+
247
282
  <Variant title="Navigation · Pill nav with dropdown and dot">
248
283
  <div style="padding: 2rem;">
249
284
  <AppTopBar