@morscherlab/mint-sdk 1.3.0-beta.5 → 1.3.0-beta.7
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.
- package/dist/{ResourcePickerListInternal-BEXnyBNz.js → ResourcePickerListInternal-CFAw4vTZ.js} +20 -17
- package/dist/ResourcePickerListInternal-CFAw4vTZ.js.map +1 -0
- package/dist/components/SettingsModal.schema.d.ts +1 -1
- package/dist/components/SettingsModal.vue.d.ts +2 -0
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +3 -3
- package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +9 -3
- package/dist/{components-BTzcqrJp.js → components-GDDvof8D.js} +19 -15
- package/dist/components-GDDvof8D.js.map +1 -0
- package/dist/composables/index.js +3 -3
- package/dist/composables/usePlatformContext.d.ts +3 -0
- package/dist/{composables-Doqb7g1z.js → composables-D6uqp0UF.js} +3 -3
- package/dist/{composables-Doqb7g1z.js.map → composables-D6uqp0UF.js.map} +1 -1
- package/dist/index.js +5 -5
- package/dist/install.js +1 -1
- package/dist/styles.css +114 -115
- package/dist/templates/index.js +1 -1
- package/dist/{templates-DgAG5kMq.js → templates-BU1pet28.js} +31 -44
- package/dist/templates-BU1pet28.js.map +1 -0
- package/dist/types/components.d.ts +4 -0
- package/dist/types/platform.d.ts +2 -0
- package/dist/{validation-DILksa0c.js → validation-Dmp9Q5W0.js} +2 -2
- package/dist/{validation-DILksa0c.js.map → validation-Dmp9Q5W0.js.map} +1 -1
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +8 -0
- package/src/__tests__/components/ExperimentSelectorModal.test.ts +12 -5
- package/src/__tests__/components/FileUploader.test.ts +6 -9
- package/src/__tests__/components/ResourcePickerListInternal.test.ts +23 -4
- package/src/__tests__/components/SettingsModal.test.ts +22 -0
- package/src/__tests__/styles/controlRefreshRules.test.ts +22 -3
- package/src/__tests__/styles/menusShellRefresh.test.ts +9 -5
- package/src/__tests__/templates/templatesDeprecation.test.ts +8 -1
- package/src/components/AppTopBar.vue +5 -1
- package/src/components/ExperimentSelectorModal.vue +4 -1
- package/src/components/FileUploader.vue +30 -46
- package/src/components/SettingsModal.schema.ts +4 -2
- package/src/components/SettingsModal.vue +4 -2
- package/src/components/index.ts +3 -3
- package/src/components/internal/ResourcePickerListInternal.vue +21 -27
- package/src/styles/components/app-page-selector.css +3 -3
- package/src/styles/components/app-top-bar.css +16 -12
- package/src/styles/components/experiment-selector-modal.css +3 -9
- package/src/styles/components/file-uploader.css +22 -55
- package/src/styles/components/resource-picker-list.css +70 -36
- package/src/types/components.ts +4 -0
- package/src/types/platform.ts +2 -0
- package/dist/ResourcePickerListInternal-BEXnyBNz.js.map +0 -1
- package/dist/components-BTzcqrJp.js.map +0 -1
- package/dist/templates-DgAG5kMq.js.map +0 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
align-items: center;
|
|
6
6
|
gap: 0.5rem;
|
|
7
7
|
flex-wrap: wrap;
|
|
8
|
+
padding: 0 1.25rem;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
.mint-experiment-selector__filter-select {
|
|
@@ -65,14 +66,6 @@ html.dark .mint-experiment-selector__filters-toggle--active {
|
|
|
65
66
|
flex-shrink: 0;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
/* Advanced filters row */
|
|
69
|
-
.mint-experiment-selector__filters-advanced {
|
|
70
|
-
padding: 0.625rem;
|
|
71
|
-
border: 1px solid var(--border-light);
|
|
72
|
-
border-radius: var(--radius-md);
|
|
73
|
-
background-color: color-mix(in srgb, var(--bg-secondary) 72%, transparent);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
69
|
/* Group toggle checkbox label */
|
|
77
70
|
.mint-experiment-selector__group-toggle {
|
|
78
71
|
display: inline-flex;
|
|
@@ -103,7 +96,8 @@ html.dark .mint-experiment-selector__filters-toggle--active {
|
|
|
103
96
|
.mint-experiment-selector__footer {
|
|
104
97
|
display: flex;
|
|
105
98
|
justify-content: flex-start;
|
|
106
|
-
padding
|
|
99
|
+
padding: 0.5rem 1.25rem 0.75rem;
|
|
100
|
+
border-top: 1px solid var(--border-light);
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
.mint-experiment-selector__clear-btn {
|
|
@@ -14,113 +14,80 @@
|
|
|
14
14
|
|
|
15
15
|
.mint-file-uploader__dropzone {
|
|
16
16
|
position: relative;
|
|
17
|
-
border:
|
|
17
|
+
border: 2px dashed var(--border-color);
|
|
18
18
|
border-radius: var(--radius-lg);
|
|
19
19
|
cursor: pointer;
|
|
20
20
|
background: var(--bg-secondary);
|
|
21
21
|
transition: border-color 0.15s ease, background-color 0.15s ease;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
/* 2g: hover only changes the surface; the border change is reserved for dragover. */
|
|
25
24
|
.mint-file-uploader__dropzone:hover {
|
|
26
|
-
|
|
25
|
+
border-color: var(--color-primary);
|
|
26
|
+
background: color-mix(in srgb, var(--color-primary) 3%, var(--bg-secondary));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.mint-file-uploader__dropzone:focus-visible {
|
|
30
|
-
outline:
|
|
31
|
-
|
|
30
|
+
outline: 2px solid var(--color-primary);
|
|
31
|
+
outline-offset: 2px;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
.mint-file-uploader__dropzone--dragover
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
background: var(--color-primary-soft);
|
|
34
|
+
.mint-file-uploader__dropzone--dragover {
|
|
35
|
+
border-color: var(--color-primary);
|
|
36
|
+
background: color-mix(in srgb, var(--color-primary) 5%, var(--bg-secondary));
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
.mint-file-uploader__dropzone--disabled
|
|
41
|
-
.mint-file-uploader__dropzone--disabled:hover {
|
|
42
|
-
background: var(--bg-tertiary);
|
|
39
|
+
.mint-file-uploader__dropzone--disabled {
|
|
43
40
|
opacity: var(--mint-disabled-opacity);
|
|
44
41
|
cursor: not-allowed;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
.mint-file-uploader__dropzone--sm {
|
|
48
|
-
padding:
|
|
45
|
+
padding: 1.25rem;
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
.mint-file-uploader__dropzone--md {
|
|
52
|
-
padding: 1.
|
|
49
|
+
padding: 1.5rem;
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
.mint-file-uploader__dropzone--lg {
|
|
56
|
-
padding:
|
|
53
|
+
padding: 2rem;
|
|
57
54
|
}
|
|
58
55
|
|
|
59
56
|
/* ==========================================================================
|
|
60
|
-
Content area
|
|
57
|
+
Content area
|
|
61
58
|
========================================================================== */
|
|
62
59
|
|
|
63
60
|
.mint-file-uploader__content {
|
|
64
61
|
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
65
63
|
align-items: center;
|
|
66
|
-
|
|
64
|
+
text-align: center;
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
.mint-file-uploader__input {
|
|
70
68
|
display: none;
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
.mint-file-uploader__icon
|
|
74
|
-
display: flex;
|
|
75
|
-
align-items: center;
|
|
76
|
-
justify-content: center;
|
|
77
|
-
flex-shrink: 0;
|
|
71
|
+
.mint-file-uploader__icon {
|
|
78
72
|
width: 2rem;
|
|
79
73
|
height: 2rem;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
color: var(--text-secondary);
|
|
83
|
-
transition: background-color 0.15s ease, color 0.15s ease;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.mint-file-uploader__dropzone--dragover .mint-file-uploader__icon-tile {
|
|
87
|
-
background: var(--color-primary);
|
|
88
|
-
color: white;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.mint-file-uploader__icon {
|
|
92
|
-
width: 1rem;
|
|
93
|
-
height: 1rem;
|
|
94
|
-
stroke-width: 1.8;
|
|
74
|
+
color: var(--text-muted);
|
|
75
|
+
margin-bottom: 0.5rem;
|
|
95
76
|
}
|
|
96
77
|
|
|
97
|
-
.mint-file-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
gap: 0.125rem;
|
|
101
|
-
min-width: 0;
|
|
78
|
+
.mint-file-uploader__dropzone:hover .mint-file-uploader__icon,
|
|
79
|
+
.mint-file-uploader__dropzone--dragover .mint-file-uploader__icon {
|
|
80
|
+
color: var(--color-primary);
|
|
102
81
|
}
|
|
103
82
|
|
|
104
83
|
.mint-file-uploader__text {
|
|
105
|
-
color: var(--text-
|
|
84
|
+
color: var(--text-secondary);
|
|
106
85
|
font-size: 0.8125rem;
|
|
107
86
|
font-weight: 500;
|
|
108
87
|
margin: 0;
|
|
109
88
|
padding: 0;
|
|
110
89
|
}
|
|
111
90
|
|
|
112
|
-
.mint-file-uploader__dropzone--dragover .mint-file-uploader__text {
|
|
113
|
-
color: var(--_ink-primary);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.mint-file-uploader__formats {
|
|
117
|
-
color: var(--text-secondary);
|
|
118
|
-
font-family: var(--font-mono);
|
|
119
|
-
font-size: 0.6875rem;
|
|
120
|
-
margin: 0;
|
|
121
|
-
padding: 0;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
91
|
/* ==========================================================================
|
|
125
92
|
Actions slot
|
|
126
93
|
========================================================================== */
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
/* ResourcePickerList
|
|
1
|
+
/* ResourcePickerList: shared list for ExperimentSelectorModal and ArtifactSelectorModal.
|
|
2
|
+
No frame of its own (the modal is the card); rows are inset and rounded, groups are
|
|
3
|
+
pinned bars. */
|
|
4
|
+
|
|
5
|
+
/* The modal is the only card: the list runs edge to edge, and the toolbar, group
|
|
6
|
+
bars and row text keep the modal's 1.25rem gutter themselves. */
|
|
7
|
+
.mint-modal__body:has(> .mint-resource-picker) {
|
|
8
|
+
padding: 0;
|
|
9
|
+
}
|
|
10
|
+
.mint-modal__container:has(.mint-resource-picker) .mint-modal__header {
|
|
11
|
+
border-bottom: none;
|
|
12
|
+
padding-bottom: 0.75rem;
|
|
13
|
+
}
|
|
2
14
|
|
|
3
15
|
.mint-resource-picker {
|
|
4
16
|
display: flex;
|
|
@@ -11,6 +23,7 @@
|
|
|
11
23
|
align-items: center;
|
|
12
24
|
flex-wrap: wrap;
|
|
13
25
|
gap: 0.5rem;
|
|
26
|
+
padding: 0 1.25rem;
|
|
14
27
|
}
|
|
15
28
|
.mint-resource-picker__search {
|
|
16
29
|
flex: 1;
|
|
@@ -20,12 +33,10 @@
|
|
|
20
33
|
.mint-resource-picker__frame {
|
|
21
34
|
display: flex;
|
|
22
35
|
flex-direction: column;
|
|
23
|
-
|
|
24
|
-
border: 1px solid var(--border-color);
|
|
25
|
-
border-radius: var(--radius-md);
|
|
26
|
-
background-color: var(--bg-card);
|
|
36
|
+
border-top: 1px solid var(--border-color);
|
|
27
37
|
}
|
|
28
38
|
.mint-resource-picker__list {
|
|
39
|
+
padding-bottom: 0.5rem;
|
|
29
40
|
max-height: min(28rem, calc(100vh - 16rem));
|
|
30
41
|
overflow-y: auto;
|
|
31
42
|
overscroll-behavior: contain;
|
|
@@ -38,14 +49,17 @@
|
|
|
38
49
|
gap: 0.5rem;
|
|
39
50
|
flex-shrink: 0;
|
|
40
51
|
width: 100%;
|
|
52
|
+
position: sticky;
|
|
53
|
+
top: 0;
|
|
54
|
+
z-index: 1;
|
|
41
55
|
height: 30px;
|
|
42
|
-
padding: 0
|
|
56
|
+
padding: 0 1.25rem;
|
|
43
57
|
border: 0;
|
|
44
58
|
border-bottom: 1px solid var(--border-light);
|
|
45
59
|
background-color: var(--bg-primary);
|
|
46
60
|
font-family: inherit;
|
|
47
61
|
font-size: 12px;
|
|
48
|
-
font-weight:
|
|
62
|
+
font-weight: 600;
|
|
49
63
|
color: var(--text-secondary);
|
|
50
64
|
text-align: left;
|
|
51
65
|
cursor: pointer;
|
|
@@ -77,24 +91,25 @@
|
|
|
77
91
|
.mint-resource-picker__group-count {
|
|
78
92
|
font: 11px var(--font-mono);
|
|
79
93
|
font-variant-numeric: tabular-nums;
|
|
94
|
+
color: var(--text-muted);
|
|
80
95
|
}
|
|
81
96
|
|
|
82
97
|
.mint-resource-picker__row {
|
|
83
98
|
display: grid;
|
|
84
|
-
grid-template-columns: minmax(0, 1fr)
|
|
99
|
+
grid-template-columns: minmax(0, 1fr);
|
|
100
|
+
grid-auto-flow: column;
|
|
101
|
+
grid-auto-columns: auto;
|
|
85
102
|
align-items: center;
|
|
86
|
-
gap:
|
|
103
|
+
gap: 12px;
|
|
87
104
|
box-sizing: border-box;
|
|
88
105
|
flex-shrink: 0;
|
|
89
|
-
min-height:
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
min-height: 56px;
|
|
107
|
+
margin: 2px 0.5rem;
|
|
108
|
+
padding: 10px 12px;
|
|
109
|
+
border-radius: var(--radius-md);
|
|
92
110
|
cursor: pointer;
|
|
93
111
|
transition: background-color 150ms ease;
|
|
94
112
|
}
|
|
95
|
-
.mint-resource-picker__row:last-child {
|
|
96
|
-
border-bottom: 0;
|
|
97
|
-
}
|
|
98
113
|
.mint-resource-picker__row:hover {
|
|
99
114
|
background-color: var(--bg-hover);
|
|
100
115
|
}
|
|
@@ -110,7 +125,7 @@
|
|
|
110
125
|
.mint-resource-picker__text {
|
|
111
126
|
display: flex;
|
|
112
127
|
flex-direction: column;
|
|
113
|
-
gap:
|
|
128
|
+
gap: 4px;
|
|
114
129
|
min-width: 0;
|
|
115
130
|
line-height: 1.25;
|
|
116
131
|
}
|
|
@@ -118,18 +133,49 @@
|
|
|
118
133
|
overflow: hidden;
|
|
119
134
|
text-overflow: ellipsis;
|
|
120
135
|
white-space: nowrap;
|
|
121
|
-
font-size:
|
|
122
|
-
font-weight:
|
|
136
|
+
font-size: 15px;
|
|
137
|
+
font-weight: 600;
|
|
123
138
|
color: var(--text-primary);
|
|
124
139
|
}
|
|
125
140
|
.mint-resource-picker__row--selected .mint-resource-picker__title {
|
|
126
141
|
color: var(--_ink-primary);
|
|
127
142
|
}
|
|
128
|
-
.mint-resource-picker__code
|
|
143
|
+
.mint-resource-picker__code {
|
|
144
|
+
margin-right: 0.5rem;
|
|
145
|
+
}
|
|
146
|
+
.mint-resource-picker__aside {
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: column;
|
|
149
|
+
align-items: flex-end;
|
|
150
|
+
gap: 4px;
|
|
151
|
+
line-height: 1.25;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
}
|
|
129
154
|
.mint-resource-picker__date {
|
|
130
|
-
font
|
|
155
|
+
font: 12px var(--font-mono);
|
|
131
156
|
font-variant-numeric: tabular-nums;
|
|
157
|
+
color: var(--text-muted);
|
|
158
|
+
}
|
|
159
|
+
.mint-resource-picker__status {
|
|
160
|
+
display: inline-flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
gap: 5px;
|
|
163
|
+
font-size: 12px;
|
|
164
|
+
font-weight: 500;
|
|
165
|
+
color: var(--text-secondary);
|
|
132
166
|
}
|
|
167
|
+
.mint-resource-picker__status::before {
|
|
168
|
+
content: '';
|
|
169
|
+
width: 6px;
|
|
170
|
+
height: 6px;
|
|
171
|
+
border-radius: 50%;
|
|
172
|
+
background-color: currentColor;
|
|
173
|
+
}
|
|
174
|
+
.mint-resource-picker__status--primary { color: var(--_ink-primary); }
|
|
175
|
+
.mint-resource-picker__status--success { color: var(--mint-success); }
|
|
176
|
+
.mint-resource-picker__status--warning { color: var(--mint-warning); }
|
|
177
|
+
.mint-resource-picker__status--error { color: var(--mint-error); }
|
|
178
|
+
.mint-resource-picker__status--info { color: var(--mint-info); }
|
|
133
179
|
.mint-resource-picker__meta {
|
|
134
180
|
overflow: hidden;
|
|
135
181
|
text-overflow: ellipsis;
|
|
@@ -142,29 +188,17 @@
|
|
|
142
188
|
align-items: center;
|
|
143
189
|
gap: 4px;
|
|
144
190
|
}
|
|
145
|
-
.mint-resource-picker__check-slot {
|
|
146
|
-
display: flex;
|
|
147
|
-
width: 14px;
|
|
148
|
-
}
|
|
149
|
-
.mint-resource-picker__check {
|
|
150
|
-
width: 14px;
|
|
151
|
-
height: 14px;
|
|
152
|
-
color: var(--color-primary);
|
|
153
|
-
}
|
|
154
191
|
|
|
155
192
|
.mint-resource-picker__skeleton-row {
|
|
156
193
|
display: flex;
|
|
157
194
|
flex-direction: column;
|
|
158
195
|
justify-content: center;
|
|
159
|
-
gap:
|
|
160
|
-
min-height:
|
|
161
|
-
padding:
|
|
162
|
-
border-bottom: 1px solid var(--border-light);
|
|
163
|
-
}
|
|
164
|
-
.mint-resource-picker__skeleton-row:last-child {
|
|
165
|
-
border-bottom: 0;
|
|
196
|
+
gap: 8px;
|
|
197
|
+
min-height: 56px;
|
|
198
|
+
padding: 10px 1.25rem;
|
|
166
199
|
}
|
|
167
200
|
.mint-resource-picker__error {
|
|
201
|
+
margin: 0 1.25rem 1.25rem;
|
|
168
202
|
padding: 0.75rem;
|
|
169
203
|
border: 1px solid var(--mint-error-border);
|
|
170
204
|
border-radius: var(--radius-md);
|
package/src/types/components.ts
CHANGED
|
@@ -211,6 +211,8 @@ export interface TopBarSettingsConfig {
|
|
|
211
211
|
title?: string
|
|
212
212
|
tabs?: SettingsTabInput[]
|
|
213
213
|
showAppearance?: boolean
|
|
214
|
+
/** List Appearance before the other tabs and open on it. */
|
|
215
|
+
appearanceFirst?: boolean
|
|
214
216
|
size?: 'md' | 'lg' | 'xl'
|
|
215
217
|
layout?: SettingsModalLayout
|
|
216
218
|
/** Schema-driven config — when set, fields auto-render via SDK form components. */
|
|
@@ -500,6 +502,8 @@ export interface SettingsTab extends AccessControlled {
|
|
|
500
502
|
description?: string
|
|
501
503
|
/** Optional monospace meta shown right of the tab label — a count, "2 unsaved", etc. */
|
|
502
504
|
meta?: string
|
|
505
|
+
/** Rail section heading for this tab when Appearance is shown; defaults to "Plugin". */
|
|
506
|
+
section?: string
|
|
503
507
|
}
|
|
504
508
|
|
|
505
509
|
export type SettingsTabInput = SettingsTab | string
|
package/src/types/platform.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { RoleInfo } from '../permissions'
|
|
|
4
4
|
export interface PluginInfo {
|
|
5
5
|
id: string
|
|
6
6
|
name: string
|
|
7
|
+
/** Name to show in the UI; the platform falls back to the plugin ID. Absent before MINT 1.3. */
|
|
8
|
+
display_name?: string
|
|
7
9
|
version: string
|
|
8
10
|
plugin_type?: string
|
|
9
11
|
description?: string
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResourcePickerListInternal-BEXnyBNz.js","names":["$slots","$slots"],"sources":["../src/components/BaseInput.vue","../src/components/BaseInput.vue","../src/utils/options.ts","../src/components/BaseSelect.vue","../src/components/BaseSelect.vue","../src/components/EmptyState.vue","../src/components/EmptyState.vue","../src/components/Skeleton.vue","../src/components/Skeleton.vue","../src/components/internal/ResourcePickerListInternal.vue","../src/components/internal/ResourcePickerListInternal.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a styled `<input>` supporting text/number/email types, size, error, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border.\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n min?: number\n max?: number\n step?: number\n list?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = props.type === 'number'\n ? (target.value === '' ? null : Number(target.value))\n : target.value\n emit('update:modelValue', value as string | number)\n}\n</script>\n\n<template>\n <div\n v-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n error ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n error ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Renders a styled `<input>` supporting text/number/email types, size, error, and readonly states.\n * Optional `#prefix` (bare leading glyph, e.g. a search icon) and `#suffix` (neutral unit segment) slots sit inside the field border.\n */\nimport { computed, useAttrs, useSlots, type StyleValue } from 'vue'\nimport type { InputType } from '../types'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n type?: InputType\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n autocomplete?: string\n autofocus?: boolean\n min?: number\n max?: number\n step?: number\n list?: string\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n type: 'text',\n disabled: false,\n readonly: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null]\n focus: [event: FocusEvent]\n blur: [event: FocusEvent]\n keydown: [event: KeyboardEvent]\n}>()\n\ndefineSlots<{\n /** Leading glyph inside the field border (search icon, currency, …), no segment background. */\n prefix?: () => unknown\n /** Trailing segment inside the field border, e.g. a unit (mono 12px on `--bg-primary`). */\n suffix?: () => unknown\n}>()\n\nconst attrs = useAttrs()\nconst slots = useSlots()\nconst wrapped = computed(() => Boolean(slots.prefix || slots.suffix))\n\n/** Wrapped: class/style style the group, every other attribute (id, name, aria-*) stays on the input. */\nconst inputAttrs = computed(() => {\n if (!wrapped.value) return attrs\n const { class: _class, style: _style, ...rest } = attrs\n return rest\n})\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = props.type === 'number'\n ? (target.value === '' ? null : Number(target.value))\n : target.value\n emit('update:modelValue', value as string | number)\n}\n</script>\n\n<template>\n <div\n v-if=\"wrapped\"\n :class=\"[\n 'mint-input-group',\n `mint-input-group--${size}`,\n error ? 'mint-input-group--error' : '',\n disabled ? 'mint-input-group--disabled' : '',\n attrs.class,\n ]\"\n :style=\"attrs.style as StyleValue\"\n >\n <span v-if=\"slots.prefix\" class=\"mint-input-group__prefix\"><slot name=\"prefix\" /></span>\n <input\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"['mint-input', `mint-input--${size}`, 'mint-input-group__control']\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n <span v-if=\"slots.suffix\" class=\"mint-input-group__suffix\"><slot name=\"suffix\" /></span>\n </div>\n <input\n v-else\n v-bind=\"inputAttrs\"\n :type=\"type\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :autocomplete=\"autocomplete\"\n :autofocus=\"autofocus\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :list=\"list\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-input',\n `mint-input--${size}`,\n error ? 'mint-input--error' : '',\n disabled ? 'mint-input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n @keydown=\"emit('keydown', $event)\"\n />\n</template>\n","export type OptionLike<TValue extends string | number> = {\n value: TValue\n label: string\n}\n\nexport function normalizeOptionInput<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(option: TOption | TValue): TOption {\n if (typeof option === 'object') return option\n\n return {\n value: option,\n label: String(option),\n } as TOption\n}\n\nexport function findOptionByDomValue<\n TValue extends string | number,\n TOption extends OptionLike<TValue>,\n>(options: TOption[], value: string): TOption | undefined {\n return options.find(option => String(option.value) === value)\n}\n","<script setup lang=\"ts\">\n/** Renders a native `<select>` element with size, error, and disabled states. */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n})\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput)\n)\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n emit('update:modelValue', option?.value ?? target.value)\n}\n</script>\n\n<template>\n <div v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"modelValue\"\n :disabled=\"disabled\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n error ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Renders a native `<select>` element with size, error, and disabled states. */\nimport { computed, useAttrs } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport type { SelectOption, SelectOptionInput } from '../types'\nimport { findOptionByDomValue, normalizeOptionInput } from '../utils/options'\n\ndefineOptions({ inheritAttrs: false })\n\ninterface Props {\n modelValue?: string | number\n options: SelectOptionInput<string | number>[]\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n ariaDescribedby?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n})\nconst attrs = useAttrs()\n\nconst controlAttrs = computed(() => {\n const { class: _class, style: _style, ...nativeAttrs } = attrs\n return nativeAttrs\n})\nconst wrapperAttrs = computed<Pick<HTMLAttributes, 'class' | 'style'>>(() => ({\n class: attrs.class as HTMLAttributes['class'],\n style: attrs.style as HTMLAttributes['style'],\n}))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n}>()\n\nconst normalizedOptions = computed<SelectOption<string | number>[]>(() =>\n props.options.map(normalizeOptionInput)\n)\n\nfunction handleChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const option = findOptionByDomValue(normalizedOptions.value, target.value)\n emit('update:modelValue', option?.value ?? target.value)\n}\n</script>\n\n<template>\n <div v-bind=\"wrapperAttrs\" class=\"mint-select\">\n <select\n v-bind=\"controlAttrs\"\n :value=\"modelValue\"\n :disabled=\"disabled\"\n :aria-invalid=\"error || undefined\"\n :aria-describedby=\"ariaDescribedby || undefined\"\n :class=\"[\n 'mint-select__control',\n `mint-select__control--${size}`,\n error ? 'mint-select__control--error' : '',\n disabled ? 'mint-select__control--disabled' : '',\n ]\"\n @change=\"handleChange\"\n >\n <option v-if=\"placeholder\" value=\"\" disabled>\n {{ placeholder }}\n </option>\n <option\n v-for=\"option in normalizedOptions\"\n :key=\"String(option.value)\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </option>\n </select>\n <div class=\"mint-select__icon\">\n <svg fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n color?: 'primary' | 'cta' | 'success' | 'warning' | 'error' | 'muted'\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n color: 'primary',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${color}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${color}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Empty-state placeholder with icon badge, headline, description, default slot, and optional CTA button. */\nimport BaseButton from './BaseButton.vue'\n\ninterface Props {\n title?: string\n description?: string\n iconPath?: string\n color?: 'primary' | 'cta' | 'success' | 'warning' | 'error' | 'muted'\n size?: 'sm' | 'md' | 'lg'\n variant?: 'illustrated' | 'inline'\n actionLabel?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n color: 'primary',\n size: 'md',\n variant: 'illustrated',\n})\n\nconst emit = defineEmits<{\n action: []\n}>()\n\nconst defaultIconPaths = [\n 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z',\n 'M7 11h10',\n 'M7 15h6',\n 'M7 7h8',\n]\n</script>\n\n<template>\n <div :class=\"['mint-empty-state', `mint-empty-state--${variant}`, `mint-empty-state--${size}`]\">\n <div :class=\"['mint-empty-state__icon-wrapper', `mint-empty-state__icon-wrapper--${color}`]\">\n <slot name=\"icon\">\n <svg\n class=\"mint-empty-state__icon\"\n :class=\"`mint-empty-state__icon--${color}`\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"iconPath\">\n <path :d=\"iconPath\" />\n </template>\n <template v-else>\n <path v-for=\"(d, i) in defaultIconPaths\" :key=\"i\" :d=\"d\" />\n </template>\n </svg>\n </slot>\n </div>\n <div class=\"mint-empty-state__body\">\n <h3 v-if=\"title\" class=\"mint-empty-state__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"mint-empty-state__description\">{{ description }}</p>\n <div v-if=\"$slots.default\" class=\"mint-empty-state__content\">\n <slot />\n </div>\n </div>\n <div v-if=\"actionLabel\" class=\"mint-empty-state__action\">\n <BaseButton variant=\"secondary\" @click=\"emit('action')\">\n {{ actionLabel }}\n </BaseButton>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\">\n/** Animated loading placeholder in text, circular, rectangular, or rounded variants with pulse or wave animation. */\nimport { computed } from 'vue'\n\ninterface Props {\n variant?: 'text' | 'circular' | 'rectangular' | 'rounded'\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'text',\n animation: 'wave',\n})\n\nconst style = computed(() => {\n const s: Record<string, string> = {}\n\n if (props.width) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width\n }\n\n if (props.height) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height\n }\n\n return s\n})\n\nconst classes = computed(() => [\n 'mint-skeleton',\n `mint-skeleton--${props.variant}`,\n // pulse and wave both breathe (3e); the shimmer is gone.\n props.animation === 'none' ? '' : 'skeleton-wave',\n])\n</script>\n\n<template>\n <div :class=\"classes\" :style=\"style\" />\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable, optionally grouped single-select list shared by the experiment and\n * artifact selector modals (8b): 44px two-line rows, trailing check, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, reactive, ref, useId, watch } from 'vue'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\n\nexport interface ResourcePickerRow {\n /** Identifier shown in mono before the title, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts, joined with \" · \". */\n meta?: string[]\n /** Rendered last on the second line, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n /** When set, rows render under collapsible group headers in this order. */\n groups?: { label: string; items: T[] }[] | null\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n }>(),\n {\n groups: null,\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** A second filter row under the search. */\n advanced?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst collapsed = reactive(new Set<string>())\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst visibleGroups = computed(() =>\n props.groups?.map((group) => ({\n ...group,\n rows: collapsed.has(group.label) ? [] : group.items,\n })),\n)\n/** Keyboard order: the rows on screen, top to bottom. */\nconst flat = computed(() =>\n visibleGroups.value ? visibleGroups.value.flatMap((group) => group.rows) : props.items,\n)\nconst indexByKey = computed(() => new Map(flat.value.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = flat.value[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction toggleGroup(label: string) {\n if (collapsed.has(label)) collapsed.delete(label)\n else collapsed.add(label)\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused header, filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = flat.value\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => [props.items, props.groups],\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n <slot name=\"advanced\" />\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <template v-for=\"group in visibleGroups ?? [{ label: '', items, rows: items }]\" :key=\"group.label\">\n <button\n v-if=\"visibleGroups\"\n type=\"button\"\n class=\"mint-resource-picker__group\"\n :aria-expanded=\"!collapsed.has(group.label)\"\n @click=\"toggleGroup(group.label)\"\n >\n <svg\n class=\"mint-resource-picker__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n <span class=\"mint-resource-picker__group-label\">{{ group.label }}</span>\n <span class=\"mint-resource-picker__group-count\">{{ group.items.length }}</span>\n </button>\n <div\n v-for=\"item in group.rows\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\"\n ><template v-if=\"describe(item).code\"\n ><span class=\"mint-resource-picker__code\">{{ describe(item).code }}</span> · </template\n >{{ describe(item).title }}</span\n >\n <span\n v-if=\"describe(item).meta?.length || describe(item).date\"\n class=\"mint-resource-picker__meta\"\n >{{ [...(describe(item).meta ?? [])].join(' · ')\n }}<template v-if=\"describe(item).date\"\n >{{ describe(item).meta?.length ? ' · ' : ''\n }}<span class=\"mint-resource-picker__date\">{{ describe(item).date }}</span></template\n ></span\n >\n </span>\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n <span class=\"mint-resource-picker__check-slot\" aria-hidden=\"true\">\n <svg\n v-if=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__check\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M3.5 8.5l3 3 6-7\" />\n </svg>\n </span>\n </div>\n </template>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"T\">\n/**\n * Searchable, optionally grouped single-select list shared by the experiment and\n * artifact selector modals (8b): 44px two-line rows, trailing check, skeleton,\n * error and empty states, and the combobox keyboard model (↑ ↓ Enter).\n */\nimport { computed, nextTick, reactive, ref, useId, watch } from 'vue'\nimport BaseInput from '../BaseInput.vue'\nimport Skeleton from '../Skeleton.vue'\nimport EmptyState from '../EmptyState.vue'\n\nexport interface ResourcePickerRow {\n /** Identifier shown in mono before the title, e.g. an experiment code. */\n code?: string\n title: string\n /** Second-line facts, joined with \" · \". */\n meta?: string[]\n /** Rendered last on the second line, in mono. */\n date?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[]\n /** When set, rows render under collapsible group headers in this order. */\n groups?: { label: string; items: T[] }[] | null\n itemKey: (item: T) => string | number\n describe: (item: T) => ResourcePickerRow\n selectedKey?: string | number | null\n search: string\n /** Accessible name of the list; the search field is labelled \"Search {label}\". */\n label: string\n placeholder?: string\n loading?: boolean\n error?: string | null\n emptyTitle?: string\n emptyDescription?: string\n }>(),\n {\n groups: null,\n selectedKey: null,\n placeholder: 'Search…',\n loading: false,\n error: null,\n emptyTitle: 'Nothing found',\n emptyDescription: 'Try adjusting your search or filters.',\n },\n)\nconst emit = defineEmits<{\n select: [item: T]\n 'update:search': [value: string]\n}>()\ndefineSlots<{\n /** Extra filters on the search row. */\n filters?: () => unknown\n /** A second filter row under the search. */\n advanced?: () => unknown\n /** Row controls before the check; keys pressed inside them never select the row. */\n actions?: (props: { item: T }) => unknown\n}>()\n\nconst listId = `mint-resource-picker-${useId().replace(/:/g, '')}`\nconst collapsed = reactive(new Set<string>())\nconst activeIndex = ref(-1)\nconst listRef = ref<HTMLElement | null>(null)\n\nconst visibleGroups = computed(() =>\n props.groups?.map((group) => ({\n ...group,\n rows: collapsed.has(group.label) ? [] : group.items,\n })),\n)\n/** Keyboard order: the rows on screen, top to bottom. */\nconst flat = computed(() =>\n visibleGroups.value ? visibleGroups.value.flatMap((group) => group.rows) : props.items,\n)\nconst indexByKey = computed(() => new Map(flat.value.map((item, i) => [props.itemKey(item), i])))\nconst showList = computed(() => !props.loading && !props.error && props.items.length > 0)\n\nfunction optionId(item: T): string {\n return `${listId}-${props.itemKey(item)}`\n}\nconst activeDescendant = computed(() => {\n const item = flat.value[activeIndex.value]\n return item === undefined ? undefined : optionId(item)\n})\n\nfunction indexOf(item: T): number {\n return indexByKey.value.get(props.itemKey(item)) ?? -1\n}\nfunction toggleGroup(label: string) {\n if (collapsed.has(label)) collapsed.delete(label)\n else collapsed.add(label)\n}\nfunction keydown(event: KeyboardEvent) {\n // Keys belong to the search combobox; a focused header, filter or row action keeps its own Enter.\n const target = event.target as HTMLElement | null\n if (target !== event.currentTarget && !target?.closest('.mint-resource-picker__search')) return\n const rows = flat.value\n if (!rows.length) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n activeIndex.value =\n event.key === 'ArrowDown'\n ? Math.min(activeIndex.value + 1, rows.length - 1)\n : Math.max(activeIndex.value - 1, 0)\n nextTick(() =>\n listRef.value\n ?.querySelector('.mint-resource-picker__row--active')\n ?.scrollIntoView({ block: 'nearest' }),\n )\n } else if (event.key === 'Enter' && rows[activeIndex.value] !== undefined) {\n event.preventDefault()\n emit('select', rows[activeIndex.value]!)\n }\n}\n\nwatch(\n () => [props.items, props.groups],\n () => {\n activeIndex.value = -1\n },\n)\n</script>\n\n<template>\n <div class=\"mint-resource-picker\" @keydown=\"keydown\">\n <div class=\"mint-resource-picker__toolbar\">\n <BaseInput\n class=\"mint-resource-picker__search\"\n :model-value=\"search\"\n :placeholder=\"placeholder\"\n size=\"sm\"\n type=\"search\"\n role=\"combobox\"\n :aria-label=\"`Search ${label.toLowerCase()}`\"\n :aria-expanded=\"showList\"\n :aria-controls=\"listId\"\n :aria-activedescendant=\"activeDescendant\"\n @update:model-value=\"emit('update:search', String($event ?? ''))\"\n >\n <template #prefix>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" aria-hidden=\"true\">\n <path d=\"M7 11.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zM10.5 10.5L14 14\" />\n </svg>\n </template>\n </BaseInput>\n <slot name=\"filters\" />\n </div>\n <slot name=\"advanced\" />\n\n <div v-if=\"loading\" class=\"mint-resource-picker__frame\" aria-busy=\"true\">\n <div v-for=\"n in 4\" :key=\"n\" class=\"mint-resource-picker__skeleton-row\">\n <Skeleton :width=\"`${40 + n * 10}%`\" height=\"0.75rem\" />\n <Skeleton width=\"30%\" height=\"0.625rem\" />\n </div>\n </div>\n <div v-else-if=\"error\" class=\"mint-resource-picker__error\" role=\"alert\">{{ error }}</div>\n <EmptyState\n v-else-if=\"!items.length\"\n :title=\"emptyTitle\"\n :description=\"emptyDescription\"\n size=\"sm\"\n />\n <div\n v-else\n :id=\"listId\"\n ref=\"listRef\"\n class=\"mint-resource-picker__frame mint-resource-picker__list\"\n role=\"listbox\"\n :aria-label=\"label\"\n >\n <template v-for=\"group in visibleGroups ?? [{ label: '', items, rows: items }]\" :key=\"group.label\">\n <button\n v-if=\"visibleGroups\"\n type=\"button\"\n class=\"mint-resource-picker__group\"\n :aria-expanded=\"!collapsed.has(group.label)\"\n @click=\"toggleGroup(group.label)\"\n >\n <svg\n class=\"mint-resource-picker__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n <span class=\"mint-resource-picker__group-label\">{{ group.label }}</span>\n <span class=\"mint-resource-picker__group-count\">{{ group.items.length }}</span>\n </button>\n <div\n v-for=\"item in group.rows\"\n :id=\"optionId(item)\"\n :key=\"itemKey(item)\"\n role=\"option\"\n :aria-selected=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__row\"\n :class=\"{\n 'mint-resource-picker__row--selected': itemKey(item) === selectedKey,\n 'mint-resource-picker__row--active': indexOf(item) === activeIndex,\n }\"\n @click=\"emit('select', item)\"\n @mouseenter=\"activeIndex = indexOf(item)\"\n >\n <span class=\"mint-resource-picker__text\">\n <span class=\"mint-resource-picker__title\"\n ><template v-if=\"describe(item).code\"\n ><span class=\"mint-resource-picker__code\">{{ describe(item).code }}</span> · </template\n >{{ describe(item).title }}</span\n >\n <span\n v-if=\"describe(item).meta?.length || describe(item).date\"\n class=\"mint-resource-picker__meta\"\n >{{ [...(describe(item).meta ?? [])].join(' · ')\n }}<template v-if=\"describe(item).date\"\n >{{ describe(item).meta?.length ? ' · ' : ''\n }}<span class=\"mint-resource-picker__date\">{{ describe(item).date }}</span></template\n ></span\n >\n </span>\n <span v-if=\"$slots.actions\" class=\"mint-resource-picker__actions\" @click.stop>\n <slot name=\"actions\" :item=\"item\" />\n </span>\n <span class=\"mint-resource-picker__check-slot\" aria-hidden=\"true\">\n <svg\n v-if=\"itemKey(item) === selectedKey\"\n class=\"mint-resource-picker__check\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M3.5 8.5l3 3 6-7\" />\n </svg>\n </span>\n </div>\n </template>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|