@morscherlab/mint-sdk 1.0.0-alpha.9 → 1.0.0-beta.2

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 (81) hide show
  1. package/dist/__tests__/components/PluginIcon.test.d.ts +1 -0
  2. package/dist/components/AppTopBar.vue.d.ts +2 -0
  3. package/dist/components/BaseButton.vue.d.ts +1 -1
  4. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  5. package/dist/components/BaseInput.vue.d.ts +1 -1
  6. package/dist/components/BasePill.vue.d.ts +1 -1
  7. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  8. package/dist/components/BaseSelect.vue.d.ts +1 -1
  9. package/dist/components/BaseSlider.vue.d.ts +1 -1
  10. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  11. package/dist/components/BaseToggle.vue.d.ts +1 -1
  12. package/dist/components/ColorSlider.vue.d.ts +1 -1
  13. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  14. package/dist/components/DatePicker.vue.d.ts +1 -1
  15. package/dist/components/DateTimePicker.vue.d.ts +1 -1
  16. package/dist/components/Divider.vue.d.ts +1 -1
  17. package/dist/components/DropdownButton.vue.d.ts +1 -1
  18. package/dist/components/FileUploader.vue.d.ts +1 -1
  19. package/dist/components/FormulaInput.vue.d.ts +1 -1
  20. package/dist/components/IconButton.vue.d.ts +1 -1
  21. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  22. package/dist/components/MultiSelect.vue.d.ts +1 -1
  23. package/dist/components/NumberInput.vue.d.ts +1 -1
  24. package/dist/components/PluginIcon.vue.d.ts +11 -0
  25. package/dist/components/ProgressBar.vue.d.ts +1 -1
  26. package/dist/components/ReagentEditor.vue.d.ts +1 -1
  27. package/dist/components/ResourceCard.vue.d.ts +1 -1
  28. package/dist/components/SampleSelector.vue.d.ts +1 -1
  29. package/dist/components/ScientificNumber.vue.d.ts +1 -1
  30. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  31. package/dist/components/SettingsModal.vue.d.ts +22 -2
  32. package/dist/components/TagsInput.vue.d.ts +1 -1
  33. package/dist/components/TimePicker.vue.d.ts +1 -1
  34. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  35. package/dist/components/UnitInput.vue.d.ts +1 -1
  36. package/dist/components/WellPlate.vue.d.ts +1 -1
  37. package/dist/components/index.d.ts +1 -0
  38. package/dist/components/index.js +3 -3
  39. package/dist/{components-CzbQQPCb.js → components-_XqPEhP9.js} +572 -362
  40. package/dist/components-_XqPEhP9.js.map +1 -0
  41. package/dist/composables/index.js +2 -2
  42. package/dist/composables/usePlatformContext.d.ts +3 -0
  43. package/dist/{composables-BXklV5ii.js → composables-tiZqLu1M.js} +2 -2
  44. package/dist/{composables-BXklV5ii.js.map → composables-tiZqLu1M.js.map} +1 -1
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +4 -4
  47. package/dist/install.js +2 -2
  48. package/dist/stores/auth.d.ts +1 -1
  49. package/dist/styles.css +896 -553
  50. package/dist/types/components.d.ts +39 -0
  51. package/dist/types/index.d.ts +1 -1
  52. package/dist/types/platform.d.ts +1 -0
  53. package/dist/{useScheduleDrag-CxBeqYcu.js → useScheduleDrag-CA9sGNJG.js} +4000 -4000
  54. package/dist/useScheduleDrag-CA9sGNJG.js.map +1 -0
  55. package/package.json +1 -1
  56. package/src/__tests__/components/AppTopBar.test.ts +31 -13
  57. package/src/__tests__/components/PluginIcon.test.ts +119 -0
  58. package/src/components/AppTopBar.vue +32 -27
  59. package/src/components/PluginIcon.story.vue +71 -0
  60. package/src/components/PluginIcon.vue +88 -0
  61. package/src/components/SettingsModal.story.vue +337 -45
  62. package/src/components/SettingsModal.vue +251 -64
  63. package/src/components/index.ts +1 -0
  64. package/src/index.ts +4 -0
  65. package/src/styles/components/app-pill-nav.css +1 -2
  66. package/src/styles/components/app-top-bar.css +1 -2
  67. package/src/styles/components/button.css +3 -7
  68. package/src/styles/components/dropdown-button.css +4 -4
  69. package/src/styles/components/input.css +4 -5
  70. package/src/styles/components/number-input.css +3 -3
  71. package/src/styles/components/plugin-icon.css +38 -0
  72. package/src/styles/components/segmented-control.css +4 -7
  73. package/src/styles/components/settings-modal.css +184 -0
  74. package/src/styles/components/tabs.css +1 -2
  75. package/src/styles/components/textarea.css +4 -5
  76. package/src/styles/components/unit-input.css +3 -3
  77. package/src/types/components.ts +42 -0
  78. package/src/types/index.ts +3 -0
  79. package/src/types/platform.ts +1 -0
  80. package/dist/components-CzbQQPCb.js.map +0 -1
  81. package/dist/useScheduleDrag-CxBeqYcu.js.map +0 -1
@@ -93,3 +93,187 @@ html.dark .mint-settings-modal__option-btn--active {
93
93
  margin-bottom: 0 !important;
94
94
  padding: 0 !important;
95
95
  }
96
+
97
+ /* ─────────────────────────────────────────────────────────────────────
98
+ * Schema-driven content grid (used by both layouts)
99
+ * Cols come from `--mint-settings-cols` set inline by the component;
100
+ * keeps the data binding minimal and the styling in one place.
101
+ * ───────────────────────────────────────────────────────────────────── */
102
+
103
+ .mint-settings-modal__group-grid {
104
+ display: grid;
105
+ gap: 1rem;
106
+ grid-template-columns: repeat(var(--mint-settings-cols, 1), minmax(0, 1fr));
107
+ }
108
+
109
+ /* ─────────────────────────────────────────────────────────────────────
110
+ * Vertical layout — sidebar rail + content pane (opt-in via layout="vertical")
111
+ * Designed for complex plugins with 5+ setting groups. Existing horizontal
112
+ * classes above are deliberately untouched.
113
+ * ───────────────────────────────────────────────────────────────────── */
114
+
115
+ .mint-settings-modal--vertical {
116
+ flex-direction: row;
117
+ gap: 1.25rem;
118
+ align-items: stretch;
119
+ min-height: 22rem;
120
+ }
121
+
122
+ .mint-settings-modal__rail {
123
+ flex-shrink: 0;
124
+ width: 12.5rem;
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: 0.125rem;
128
+ padding-right: 0.75rem;
129
+ border-right: 1px solid var(--border-light);
130
+ }
131
+
132
+ .mint-settings-modal__rail-item {
133
+ display: flex;
134
+ align-items: flex-start;
135
+ gap: 0.625rem;
136
+ width: 100%;
137
+ padding: 0.5rem 0.75rem;
138
+ font-size: 0.8125rem;
139
+ font-weight: 500;
140
+ color: var(--text-secondary);
141
+ background: none;
142
+ border: none;
143
+ border-radius: var(--radius-md);
144
+ cursor: pointer;
145
+ text-align: left;
146
+ transition:
147
+ color var(--mint-transition),
148
+ background-color var(--mint-transition);
149
+ }
150
+
151
+ .mint-settings-modal__rail-item:hover {
152
+ background-color: var(--bg-hover);
153
+ color: var(--text-primary);
154
+ }
155
+
156
+ .mint-settings-modal__rail-item:focus-visible {
157
+ outline: none;
158
+ box-shadow: var(--focus-ring);
159
+ }
160
+
161
+ .mint-settings-modal__rail-item--active {
162
+ color: var(--color-primary);
163
+ background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
164
+ }
165
+
166
+ html.dark .mint-settings-modal__rail-item--active {
167
+ background-color: color-mix(in srgb, var(--color-primary) 18%, transparent);
168
+ }
169
+
170
+ /* Reserved icon column keeps labels aligned whether or not icons are present */
171
+ .mint-settings-modal__rail-item-icon {
172
+ flex-shrink: 0;
173
+ width: 1rem;
174
+ height: 1rem;
175
+ display: inline-flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ margin-top: 0.0625rem;
179
+ color: currentColor;
180
+ }
181
+
182
+ .mint-settings-modal__rail-item-icon svg {
183
+ width: 100%;
184
+ height: 100%;
185
+ display: block;
186
+ }
187
+
188
+ .mint-settings-modal__rail-item-text {
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: 0.125rem;
192
+ min-width: 0;
193
+ flex: 1;
194
+ }
195
+
196
+ .mint-settings-modal__rail-item-label {
197
+ line-height: 1.3;
198
+ }
199
+
200
+ .mint-settings-modal__rail-item-description {
201
+ font-size: 0.6875rem;
202
+ font-weight: 400;
203
+ color: var(--text-muted);
204
+ line-height: 1.35;
205
+ }
206
+
207
+ .mint-settings-modal__rail-item--active .mint-settings-modal__rail-item-description {
208
+ color: color-mix(in srgb, var(--color-primary) 65%, var(--text-secondary));
209
+ }
210
+
211
+ .mint-settings-modal__pane {
212
+ flex: 1;
213
+ min-width: 0;
214
+ display: flex;
215
+ flex-direction: column;
216
+ }
217
+
218
+ .mint-settings-modal__pane-header {
219
+ margin-bottom: 1rem;
220
+ padding-bottom: 0.75rem;
221
+ border-bottom: 1px solid var(--border-light);
222
+ }
223
+
224
+ .mint-settings-modal__pane-title {
225
+ font-size: 0.875rem;
226
+ font-weight: 600;
227
+ color: var(--text-primary);
228
+ letter-spacing: -0.005em;
229
+ margin: 0 !important;
230
+ padding: 0 !important;
231
+ line-height: 1.3;
232
+ }
233
+
234
+ .mint-settings-modal__pane-subtitle {
235
+ font-size: 0.75rem;
236
+ color: var(--text-secondary);
237
+ line-height: 1.45;
238
+ margin: 0.25rem 0 0 !important;
239
+ padding: 0 !important;
240
+ }
241
+
242
+ .mint-settings-modal__pane-body {
243
+ flex: 1;
244
+ min-height: 0;
245
+ /* Trailing breathing room so the last field doesn't hug the modal border */
246
+ padding-bottom: 0.25rem;
247
+ }
248
+
249
+ /* Mobile — collapse the rail into a horizontal scroll-strip so the modal stays usable.
250
+ * Touch targets stay ≥40px tall via 0.5rem vertical padding + 1rem text line-height. */
251
+ @media (max-width: 640px) {
252
+ .mint-settings-modal--vertical {
253
+ flex-direction: column;
254
+ gap: 0.875rem;
255
+ min-height: 0;
256
+ }
257
+
258
+ .mint-settings-modal__rail {
259
+ width: 100%;
260
+ flex-direction: row;
261
+ overflow-x: auto;
262
+ padding: 0 0 0.625rem;
263
+ border-right: none;
264
+ border-bottom: 1px solid var(--border-light);
265
+ gap: 0.25rem;
266
+ scrollbar-width: thin;
267
+ }
268
+
269
+ .mint-settings-modal__rail-item {
270
+ flex-shrink: 0;
271
+ width: auto;
272
+ padding: 0.5rem 0.75rem;
273
+ }
274
+
275
+ /* Two-line description hides on mobile so the rail strip stays compact */
276
+ .mint-settings-modal__rail-item-description {
277
+ display: none;
278
+ }
279
+ }
@@ -15,9 +15,8 @@
15
15
  border-radius: var(--radius-md);
16
16
  }
17
17
 
18
- /* 1px optical padding shift (0.16+). See CLAUDE.md § Optical Centering. */
19
18
  .mint-tab {
20
- padding: 0.4375rem 1rem 0.5625rem;
19
+ padding: 0.5rem 1rem;
21
20
  font-size: 0.875rem;
22
21
  font-weight: 500;
23
22
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
@@ -48,20 +48,19 @@
48
48
  resize: none;
49
49
  }
50
50
 
51
- /* Size variants — 1px optical padding shift (0.16+).
52
- See CLAUDE.md § Optical Centering. */
51
+ /* Size variants */
53
52
  .mint-textarea--sm {
54
- padding: 0.3125rem 0.625rem 0.4375rem;
53
+ padding: 0.375rem 0.625rem;
55
54
  font-size: 0.8125rem;
56
55
  }
57
56
 
58
57
  .mint-textarea--md {
59
- padding: 0.4375rem 0.75rem 0.5625rem;
58
+ padding: 0.5rem 0.75rem;
60
59
  font-size: 0.875rem;
61
60
  }
62
61
 
63
62
  .mint-textarea--lg {
64
- padding: 0.6875rem 1rem 0.8125rem;
63
+ padding: 0.75rem 1rem;
65
64
  font-size: 1rem;
66
65
  }
67
66
 
@@ -70,9 +70,9 @@
70
70
 
71
71
  /* Horizontal padding matches BaseInput canonical scale (10/12/16) so FormField's
72
72
  12px label indent aligns with the value text across all input types. */
73
- .mint-unit-input__value--sm { padding: 0.3125rem 0.625rem 0.4375rem; font-size: 0.875rem; }
74
- .mint-unit-input__value--md { padding: 0.4375rem 0.75rem 0.5625rem; font-size: 0.875rem; }
75
- .mint-unit-input__value--lg { padding: 0.6875rem 1rem 0.8125rem; font-size: 1rem; }
73
+ .mint-unit-input__value--sm { padding: 0.375rem 0.625rem; font-size: 0.875rem; }
74
+ .mint-unit-input__value--md { padding: 0.5rem 0.75rem; font-size: 0.875rem; }
75
+ .mint-unit-input__value--lg { padding: 0.75rem 1rem; font-size: 1rem; }
76
76
 
77
77
  /* ---------- Unit chip ---------- */
78
78
 
@@ -118,6 +118,13 @@ export interface TopBarSettingsConfig {
118
118
  tabs?: SettingsTab[]
119
119
  showAppearance?: boolean
120
120
  size?: 'md' | 'lg' | 'xl'
121
+ layout?: SettingsModalLayout
122
+ /** Schema-driven config — when set, fields auto-render via FormFieldRenderer. */
123
+ schema?: SettingsModalSchema
124
+ /** Initial values when using `schema`. AppTopBar emits `settings-values-change` on change. */
125
+ values?: Record<string, unknown>
126
+ /** Dynamic enhancements (validators, dynamic options, callbacks). Forwarded to SettingsModal. */
127
+ enhancements?: import('./form-builder').FormEnhancements
121
128
  }
122
129
 
123
130
  // TopBar pill-nav items (centered top-level navigation)
@@ -517,7 +524,42 @@ export type ConfirmVariant = 'danger' | 'warning' | 'info'
517
524
  export interface SettingsTab {
518
525
  id: string
519
526
  label: string
527
+ /**
528
+ * Inline SVG markup rendered with `v-html` in the vertical layout's rail.
529
+ * Must be trusted, plugin-author-controlled markup — never user-supplied data.
530
+ */
520
531
  icon?: string
532
+ /** Optional one-line hint shown under the label (vertical layout) and as a section subtitle in the right pane. */
533
+ description?: string
534
+ }
535
+
536
+ export type SettingsModalLayout = 'horizontal' | 'vertical'
537
+
538
+ /**
539
+ * Declarative settings group — becomes both a tab and a FormSection.
540
+ * Plugin authors describe their parameters once and the modal auto-renders
541
+ * SDK form components (BaseInput / BaseSelect / NumberInput / Toggle / …)
542
+ * via the same registry that powers FormBuilder.
543
+ */
544
+ export interface SettingsGroup {
545
+ id: string
546
+ label: string
547
+ description?: string
548
+ /**
549
+ * Inline SVG markup rendered with `v-html` in the vertical layout's rail.
550
+ * Must be trusted, plugin-author-controlled markup — never user-supplied data.
551
+ */
552
+ icon?: string
553
+ /** SDK form-builder field schemas. */
554
+ fields: import('./form-builder').FormFieldSchema[]
555
+ /** Grid columns for the rendered fields (1-3). Defaults to 1. */
556
+ columns?: 1 | 2 | 3
557
+ /** Hide the entire group (rail item + content) when this evaluates false against the form data. */
558
+ condition?: import('./form-builder').FieldCondition
559
+ }
560
+
561
+ export interface SettingsModalSchema {
562
+ groups: SettingsGroup[]
521
563
  }
522
564
 
523
565
  // ScientificNumber types
@@ -99,6 +99,9 @@ export type {
99
99
  ConfirmVariant,
100
100
  // SettingsModal types
101
101
  SettingsTab,
102
+ SettingsModalLayout,
103
+ SettingsGroup,
104
+ SettingsModalSchema,
102
105
  // ScientificNumber types
103
106
  NumberNotation,
104
107
  // UnitInput types
@@ -5,6 +5,7 @@ export interface PluginInfo {
5
5
  version: string
6
6
  description?: string
7
7
  icon?: string
8
+ color?: string
8
9
  route_prefix: string
9
10
  api_prefix: string
10
11
  nav_items?: PluginNavItem[]