@aquera/mcp-ui-render 0.0.1
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/CHANGELOG.md +437 -0
- package/CONFIGURATION.md +178 -0
- package/LICENSE +21 -0
- package/README.md +237 -0
- package/RELEASE-NOTES.md +77 -0
- package/TEST-PLAN.md +72 -0
- package/USAGE.md +100 -0
- package/package.json +52 -0
- package/src/controls.d.ts +1 -0
- package/src/controls.js +572 -0
- package/src/controls.js.map +1 -0
- package/src/elements/aq-mcp-config.d.ts +289 -0
- package/src/elements/aq-mcp-config.js +673 -0
- package/src/elements/aq-mcp-config.js.map +1 -0
- package/src/elements/aq-mcp-field.d.ts +92 -0
- package/src/elements/aq-mcp-field.js +275 -0
- package/src/elements/aq-mcp-field.js.map +1 -0
- package/src/elements/aq-mcp-section.d.ts +101 -0
- package/src/elements/aq-mcp-section.js +261 -0
- package/src/elements/aq-mcp-section.js.map +1 -0
- package/src/engine/status.d.ts +31 -0
- package/src/engine/status.js +44 -0
- package/src/engine/status.js.map +1 -0
- package/src/engine/submit.d.ts +26 -0
- package/src/engine/submit.js +37 -0
- package/src/engine/submit.js.map +1 -0
- package/src/engine/validate.d.ts +24 -0
- package/src/engine/validate.js +144 -0
- package/src/engine/validate.js.map +1 -0
- package/src/engine/values.d.ts +20 -0
- package/src/engine/values.js +42 -0
- package/src/engine/values.js.map +1 -0
- package/src/index.d.ts +18 -0
- package/src/index.js +20 -0
- package/src/index.js.map +1 -0
- package/src/mcp-ui-render.css +811 -0
- package/src/registry.d.ts +63 -0
- package/src/registry.js +39 -0
- package/src/registry.js.map +1 -0
- package/src/types.d.ts +239 -0
- package/src/types.js +8 -0
- package/src/types.js.map +1 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
/* Default "sectioned form" layout for @aquera/mcp-ui-render (design Option A):
|
|
2
|
+
* a card per section, two-column rows (label+help left, control right), an
|
|
3
|
+
* authType badge + save-target caption in the header, and a save footer per
|
|
4
|
+
* card. Styled with Nile nxtgen tokens so it inherits the host theme. Hosts may
|
|
5
|
+
* override any of these classes. Import once: import '@aquera/mcp-ui-render/styles.css'. */
|
|
6
|
+
|
|
7
|
+
.aq-mcp {
|
|
8
|
+
display: block;
|
|
9
|
+
max-width: 920px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.aq-mcp-section {
|
|
13
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
14
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
15
|
+
border-radius: 12px;
|
|
16
|
+
margin-bottom: 20px;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.aq-mcp-section__header {
|
|
21
|
+
padding: 20px 24px 14px;
|
|
22
|
+
}
|
|
23
|
+
.aq-mcp-section__title {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 10px;
|
|
27
|
+
font-size: 16px;
|
|
28
|
+
font-weight: 700;
|
|
29
|
+
color: var(--ng-colors-text-primary-900, #101828);
|
|
30
|
+
}
|
|
31
|
+
.aq-mcp-section__caption {
|
|
32
|
+
margin-top: 6px;
|
|
33
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
34
|
+
font-size: 12px;
|
|
35
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.aq-mcp-section__body {
|
|
39
|
+
padding: 0 24px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.aq-mcp-field {
|
|
43
|
+
display: grid;
|
|
44
|
+
grid-template-columns: 280px 1fr;
|
|
45
|
+
gap: 24px;
|
|
46
|
+
align-items: start;
|
|
47
|
+
padding: 18px 0;
|
|
48
|
+
border-top: 1px solid var(--ng-colors-border-secondary-alt, #f0f1f4);
|
|
49
|
+
}
|
|
50
|
+
.aq-mcp-field:first-child {
|
|
51
|
+
border-top: 0;
|
|
52
|
+
}
|
|
53
|
+
.aq-mcp-field__label {
|
|
54
|
+
font-size: 14px;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
57
|
+
}
|
|
58
|
+
.aq-mcp-field__req {
|
|
59
|
+
color: var(--ng-color-error-500, #d92d20);
|
|
60
|
+
margin-left: 2px;
|
|
61
|
+
}
|
|
62
|
+
.aq-mcp-field__help {
|
|
63
|
+
margin-top: 4px;
|
|
64
|
+
font-size: 13px;
|
|
65
|
+
font-weight: 400;
|
|
66
|
+
line-height: 1.45;
|
|
67
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
68
|
+
}
|
|
69
|
+
.aq-mcp-field__help-toggle {
|
|
70
|
+
display: inline;
|
|
71
|
+
margin-left: 4px;
|
|
72
|
+
padding: 0;
|
|
73
|
+
border: 0;
|
|
74
|
+
background: none;
|
|
75
|
+
font-size: 13px;
|
|
76
|
+
font-weight: 600;
|
|
77
|
+
color: var(--ng-colors-brand-600, #7f56d9);
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
}
|
|
80
|
+
.aq-mcp-field__control {
|
|
81
|
+
min-width: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* `input`/`textarea`/`password`/`select`/`radio` are given Nile's own `label`
|
|
85
|
+
* (see controls.ts) purely so each control wires its real, native accessible-name
|
|
86
|
+
* association (`for`/`aria-labelledby`) — Nile leaves that association
|
|
87
|
+
* `aria-hidden` when `label` is empty. This library already shows the label
|
|
88
|
+
* VISIBLY in `.aq-mcp-field__label` (the left column, §12 two-column
|
|
89
|
+
* layout), so Nile's own internal label element is visually hidden here —
|
|
90
|
+
* NOT `display:none`/`visibility:hidden`, which would also drop it from the
|
|
91
|
+
* accessibility tree and defeat the whole point; this is the standard
|
|
92
|
+
* clip-rect "visually hidden, still announced" pattern. */
|
|
93
|
+
.aq-mcp-field__control nile-input::part(form-control-label),
|
|
94
|
+
.aq-mcp-field__control nile-textarea::part(form-control-label),
|
|
95
|
+
.aq-mcp-field__control nile-select::part(form-control-label),
|
|
96
|
+
.aq-mcp-field__control nile-radio-group::part(form-control-label) {
|
|
97
|
+
position: absolute;
|
|
98
|
+
width: 1px;
|
|
99
|
+
height: 1px;
|
|
100
|
+
padding: 0;
|
|
101
|
+
margin: -1px;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
clip: rect(0, 0, 0, 0);
|
|
104
|
+
white-space: nowrap;
|
|
105
|
+
border: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* write-once secret in "set" state — shown as a STATE, not a masked value
|
|
109
|
+
(§7): the host holds the real secret and this element never sees it, so a
|
|
110
|
+
row of dots would imply there is something here to reveal. */
|
|
111
|
+
.aq-mcp-writeonce {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: 12px;
|
|
115
|
+
font-size: 14px;
|
|
116
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
117
|
+
}
|
|
118
|
+
.aq-mcp-field--dense .aq-mcp-writeonce {
|
|
119
|
+
padding: 10px 12px;
|
|
120
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
121
|
+
border-radius: 8px;
|
|
122
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
123
|
+
}
|
|
124
|
+
.aq-mcp-writeonce__lock {
|
|
125
|
+
display: inline-flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
flex: 0 0 auto;
|
|
129
|
+
width: 26px;
|
|
130
|
+
height: 26px;
|
|
131
|
+
border-radius: 7px;
|
|
132
|
+
background: var(--ng-color-success-50, #ecfdf3);
|
|
133
|
+
color: var(--ng-color-success-600, #079455);
|
|
134
|
+
}
|
|
135
|
+
.aq-mcp-writeonce__state {
|
|
136
|
+
flex: 1 1 auto;
|
|
137
|
+
font-size: 13.5px;
|
|
138
|
+
}
|
|
139
|
+
.aq-mcp-writeonce__replace {
|
|
140
|
+
flex: 0 0 auto;
|
|
141
|
+
padding: 6px 12px;
|
|
142
|
+
border: 1px solid var(--ng-colors-border-primary, #d0d5dd);
|
|
143
|
+
border-radius: 8px;
|
|
144
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
145
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
146
|
+
font: inherit;
|
|
147
|
+
font-size: 13px;
|
|
148
|
+
font-weight: 600;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
}
|
|
151
|
+
.aq-mcp-writeonce__replace:hover {
|
|
152
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.aq-mcp-section__footer {
|
|
156
|
+
display: flex;
|
|
157
|
+
justify-content: flex-end;
|
|
158
|
+
padding: 16px 24px;
|
|
159
|
+
border-top: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
160
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* `sectionsLayout: 'tabs'` (aq-mcp-config) — each section's own card loses its
|
|
164
|
+
* border/background/margin when nested in a tab panel (the tab strip already
|
|
165
|
+
* frames it), and its header drops the title line (the tab nav already shows
|
|
166
|
+
* the label) but keeps the authType badge + save-target caption inline. */
|
|
167
|
+
.aq-mcp-tabs {
|
|
168
|
+
display: block;
|
|
169
|
+
margin-bottom: 24px;
|
|
170
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
171
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
172
|
+
border-radius: 12px;
|
|
173
|
+
overflow: hidden;
|
|
174
|
+
}
|
|
175
|
+
.aq-mcp-tabs::part(nav) {
|
|
176
|
+
/* Vertical padding, not just horizontal — with only `0 24px`, tab labels
|
|
177
|
+
* sat flush against the card's top edge with no room to breathe. */
|
|
178
|
+
padding: 14px 24px 0;
|
|
179
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
180
|
+
}
|
|
181
|
+
/* `body` is nile-nav-tab-group's own documented part name for "the container
|
|
182
|
+
* where the panel content stays" (there's no per-panel `base` part). */
|
|
183
|
+
.aq-mcp-tabs::part(body) {
|
|
184
|
+
padding: 20px 24px 24px;
|
|
185
|
+
}
|
|
186
|
+
/* Vertical placement ('start'/'end'): the nav column sits directly beside the
|
|
187
|
+
* content with no card padding of its own — give it room to breathe. Column
|
|
188
|
+
* width itself comes from nile-nav-tab-group's own `width` attribute (set in
|
|
189
|
+
* aq-mcp-config.ts), not CSS — that's its documented purpose (fixed per-tab
|
|
190
|
+
* width, preventing layout shift when switching tabs). */
|
|
191
|
+
.aq-mcp-tabs[placement='start']::part(nav),
|
|
192
|
+
.aq-mcp-tabs[placement='end']::part(nav) {
|
|
193
|
+
padding: 16px 12px;
|
|
194
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
195
|
+
}
|
|
196
|
+
.aq-mcp-tabs[placement='start']::part(body),
|
|
197
|
+
.aq-mcp-tabs[placement='end']::part(body) {
|
|
198
|
+
padding: 24px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* A section's tab label: left-aligned, never wraps. In horizontal placement
|
|
202
|
+
* tabs size to their own content as normal (unconstrained) — only vertical
|
|
203
|
+
* placement gets a hard max-width + ellipsis, since that's the mode with a
|
|
204
|
+
* fixed-width nav column (`width` attribute, aq-mcp-config.ts) a long label
|
|
205
|
+
* can actually overflow. nile-nav-tab's slotted content isn't clipped by an
|
|
206
|
+
* ancestor flex container by default, so a plain `flex:1` on this element
|
|
207
|
+
* does nothing — `max-width` + `overflow:hidden` is the self-contained
|
|
208
|
+
* truncation that doesn't depend on the parent's layout. `title` (set in
|
|
209
|
+
* aq-mcp-config.ts) gives the full label on hover once truncated. */
|
|
210
|
+
.aq-mcp-tab-label {
|
|
211
|
+
display: block;
|
|
212
|
+
text-align: left;
|
|
213
|
+
}
|
|
214
|
+
.aq-mcp-tabs[placement='start'] .aq-mcp-tab-label,
|
|
215
|
+
.aq-mcp-tabs[placement='end'] .aq-mcp-tab-label {
|
|
216
|
+
max-width: 170px;
|
|
217
|
+
overflow: hidden;
|
|
218
|
+
text-overflow: ellipsis;
|
|
219
|
+
white-space: nowrap;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Tab error-indicator (tabsShowErrorIndicator, default true) — a small red
|
|
223
|
+
* dot after the tab's label, shown only once that section has an ACTUAL
|
|
224
|
+
* recorded validation error (this.errors), not merely an untouched required
|
|
225
|
+
* field — see sectionHasError()'s doc comment. Slotted as `slot="suffix"`
|
|
226
|
+
* (nile-nav-tab's own documented slot for content after the label), not the
|
|
227
|
+
* default slot — the default slot's label track gets truncated/sized
|
|
228
|
+
* independently in vertical placement, which squeezed a default-slotted dot
|
|
229
|
+
* to 0 width; `suffix` doesn't share that sizing. */
|
|
230
|
+
.aq-mcp-tab-error-dot {
|
|
231
|
+
display: inline-block;
|
|
232
|
+
width: 6px;
|
|
233
|
+
height: 6px;
|
|
234
|
+
flex: 0 0 auto;
|
|
235
|
+
margin-left: 8px;
|
|
236
|
+
border-radius: 50%;
|
|
237
|
+
background: var(--ng-color-error-500, #d92d20);
|
|
238
|
+
vertical-align: middle;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.aq-mcp-section--compact {
|
|
242
|
+
background: transparent;
|
|
243
|
+
border: none;
|
|
244
|
+
border-radius: 0;
|
|
245
|
+
margin-bottom: 0;
|
|
246
|
+
}
|
|
247
|
+
.aq-mcp-section__header--compact {
|
|
248
|
+
display: flex;
|
|
249
|
+
align-items: center;
|
|
250
|
+
gap: 12px;
|
|
251
|
+
padding: 0 0 16px;
|
|
252
|
+
border-bottom: 1px solid var(--ng-colors-border-secondary-alt, #f0f1f4);
|
|
253
|
+
margin-bottom: 4px;
|
|
254
|
+
}
|
|
255
|
+
.aq-mcp-section__header--compact .aq-mcp-section__caption {
|
|
256
|
+
margin-top: 0;
|
|
257
|
+
}
|
|
258
|
+
.aq-mcp-section--compact .aq-mcp-section__body {
|
|
259
|
+
padding: 0;
|
|
260
|
+
}
|
|
261
|
+
.aq-mcp-section--compact .aq-mcp-section__footer {
|
|
262
|
+
padding: 16px 0 0;
|
|
263
|
+
margin-top: 4px;
|
|
264
|
+
background: transparent;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ── `sectionsLayout: 'accordion'` ─────────────────────────────────────────
|
|
268
|
+
* One `nile-accordion` per section, single-open, each header summarising what
|
|
269
|
+
* is inside (field count + completion chip) so a COLLAPSED section still says
|
|
270
|
+
* whether it needs attention. The open card's body is a two-column grid of
|
|
271
|
+
* label-above-control cells — a denser shape than the label-left rows the
|
|
272
|
+
* other two layouts use, which is what makes a whole multi-section form
|
|
273
|
+
* scannable at once.
|
|
274
|
+
*
|
|
275
|
+
* Everything here is `::part()` on Nile's own components, never a descendant
|
|
276
|
+
* selector into their shadow DOM — same approach as `.aq-mcp-tabs::part(nav)`
|
|
277
|
+
* above. Token-with-hex-fallback matches the rest of this file. */
|
|
278
|
+
|
|
279
|
+
/* The dense grid wants the full container; `.aq-mcp`'s 920px cap is tuned for
|
|
280
|
+
the single-column label-left rows and would squeeze two columns into
|
|
281
|
+
unusable widths. Scoped to this layout so stacked/tabs are untouched. */
|
|
282
|
+
.aq-mcp--accordion {
|
|
283
|
+
max-width: 1180px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.aq-mcp-acc-list {
|
|
287
|
+
display: block;
|
|
288
|
+
margin-bottom: 24px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Each accordion is its own card. Nile's default is a border-TOP only (a
|
|
292
|
+
stacked list of rows); the design is separated cards, so the base part gets
|
|
293
|
+
a full border, a radius, and its own vertical rhythm. */
|
|
294
|
+
.aq-mcp-acc {
|
|
295
|
+
display: block;
|
|
296
|
+
margin-bottom: 12px;
|
|
297
|
+
}
|
|
298
|
+
.aq-mcp-acc::part(base) {
|
|
299
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
300
|
+
border-radius: 12px;
|
|
301
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
302
|
+
overflow: hidden;
|
|
303
|
+
}
|
|
304
|
+
/* No per-card edge tint: the header's own "N required left" line is the
|
|
305
|
+
signal now, and a coloured border around the whole card on top of it
|
|
306
|
+
double-reports the same fact while making a merely-incomplete section look
|
|
307
|
+
like an error. */
|
|
308
|
+
|
|
309
|
+
.aq-mcp-acc::part(header) {
|
|
310
|
+
padding: 16px 20px;
|
|
311
|
+
}
|
|
312
|
+
.aq-mcp-acc::part(summary-icon) {
|
|
313
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
314
|
+
}
|
|
315
|
+
/* Nile indents arrow-left content to clear the chevron; the grid below wants
|
|
316
|
+
the card's full width, and the header's own padding already aligns it. */
|
|
317
|
+
.aq-mcp-acc::part(content) {
|
|
318
|
+
margin-left: 0;
|
|
319
|
+
padding: 0 20px 20px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.aq-mcp-acc__summary {
|
|
323
|
+
display: flex;
|
|
324
|
+
align-items: center;
|
|
325
|
+
gap: 14px;
|
|
326
|
+
width: 100%;
|
|
327
|
+
min-width: 0;
|
|
328
|
+
}
|
|
329
|
+
/* The icon tile: a soft brand-tinted square, not a bare glyph. It gives the
|
|
330
|
+
header a fixed left anchor so titles of different lengths still line up
|
|
331
|
+
down the stack of cards. */
|
|
332
|
+
.aq-mcp-acc__icon {
|
|
333
|
+
display: inline-flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
justify-content: center;
|
|
336
|
+
flex: 0 0 auto;
|
|
337
|
+
width: 38px;
|
|
338
|
+
height: 38px;
|
|
339
|
+
border-radius: 10px;
|
|
340
|
+
background: var(--ng-colors-bg-brand-primary, #eff4ff);
|
|
341
|
+
color: var(--ng-colors-fg-brand-primary-600, #155eef);
|
|
342
|
+
}
|
|
343
|
+
.aq-mcp-acc__heading {
|
|
344
|
+
display: flex;
|
|
345
|
+
align-items: center;
|
|
346
|
+
gap: 10px;
|
|
347
|
+
min-width: 0;
|
|
348
|
+
flex: 1 1 auto;
|
|
349
|
+
}
|
|
350
|
+
.aq-mcp-acc__label {
|
|
351
|
+
font-size: 15px;
|
|
352
|
+
font-weight: 700;
|
|
353
|
+
color: var(--ng-colors-text-primary-900, #101828);
|
|
354
|
+
overflow: hidden;
|
|
355
|
+
text-overflow: ellipsis;
|
|
356
|
+
white-space: nowrap;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* Status sits beside the chevron as plain text, not a filled pill — a pill
|
|
360
|
+
here competes with the section title for the eye, and this is a readout,
|
|
361
|
+
not a control. Colour is never the only signal: each state carries both a
|
|
362
|
+
mark (check or dot) and its own words. */
|
|
363
|
+
.aq-mcp-acc__state {
|
|
364
|
+
display: inline-flex;
|
|
365
|
+
align-items: center;
|
|
366
|
+
gap: 6px;
|
|
367
|
+
flex: 0 0 auto;
|
|
368
|
+
font-size: 13px;
|
|
369
|
+
font-weight: 600;
|
|
370
|
+
white-space: nowrap;
|
|
371
|
+
}
|
|
372
|
+
.aq-mcp-acc__state--complete {
|
|
373
|
+
color: var(--ng-color-success-600, #079455);
|
|
374
|
+
}
|
|
375
|
+
.aq-mcp-acc__state--incomplete {
|
|
376
|
+
color: var(--ng-color-warning-600, #dc6803);
|
|
377
|
+
}
|
|
378
|
+
.aq-mcp-acc__dot {
|
|
379
|
+
display: inline-block;
|
|
380
|
+
width: 7px;
|
|
381
|
+
height: 7px;
|
|
382
|
+
border-radius: 50%;
|
|
383
|
+
background: currentColor;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* ── dense section body: three zones ── */
|
|
387
|
+
/* The open card splits into "things you must decide" (full width), "defaults
|
|
388
|
+
you can tune" (two-up under a rule), and boolean toggles (full-width rows).
|
|
389
|
+
See `zones()` in aq-mcp-section.ts for why this reorders the descriptor. */
|
|
390
|
+
.aq-mcp-section--dense {
|
|
391
|
+
background: transparent;
|
|
392
|
+
border: none;
|
|
393
|
+
border-radius: 0;
|
|
394
|
+
margin-bottom: 0;
|
|
395
|
+
overflow: visible;
|
|
396
|
+
}
|
|
397
|
+
.aq-mcp-section__body--dense {
|
|
398
|
+
display: block;
|
|
399
|
+
padding: 0;
|
|
400
|
+
}
|
|
401
|
+
.aq-mcp-zone {
|
|
402
|
+
display: grid;
|
|
403
|
+
grid-template-columns: minmax(0, 1fr);
|
|
404
|
+
gap: 18px;
|
|
405
|
+
align-items: start;
|
|
406
|
+
}
|
|
407
|
+
.aq-mcp-zone--toggles {
|
|
408
|
+
gap: 10px;
|
|
409
|
+
margin-top: 18px;
|
|
410
|
+
}
|
|
411
|
+
.aq-mcp-zone--defaults {
|
|
412
|
+
margin-top: 4px;
|
|
413
|
+
}
|
|
414
|
+
/* Two columns when there is room, one when there is not — WITHOUT a media
|
|
415
|
+
* query, deliberately. What matters is the width of THIS GRID, not of the
|
|
416
|
+
* window: the same form is ~1180px wide on its own page and ~400px next to a
|
|
417
|
+
* docked side panel at an identical viewport, and a media query cannot tell
|
|
418
|
+
* those two apart. `auto-fit` reacts to the real container instead.
|
|
419
|
+
*
|
|
420
|
+
* Why the track list is shaped this way, and why the 13 is not a typo for 12:
|
|
421
|
+
*
|
|
422
|
+
* gap g = 24px
|
|
423
|
+
* min track m = max(240px, C/2 - 13px) for a container of width C
|
|
424
|
+
* columns n = floor((C + g) / (m + g))
|
|
425
|
+
*
|
|
426
|
+
* The `C/2` term is what CAPS the count at two: three tracks would need
|
|
427
|
+
* 3m + 2g = 1.5C - 39 + 48, which exceeds C for every C, so a very wide
|
|
428
|
+
* container gets WIDER columns rather than a third one. The `240px` floor is
|
|
429
|
+
* what drops it to one column when a half-width cell would be too cramped for
|
|
430
|
+
* a label, control and hint line.
|
|
431
|
+
*
|
|
432
|
+
* The subtraction must be slightly MORE than half the gap. At the exact value
|
|
433
|
+
* (12px = g/2), two tracks plus the gap come to precisely 100% of the
|
|
434
|
+
* container — measured live at 834px available against 834px needed — and
|
|
435
|
+
* that dead heat is decided by subpixel rounding, which loses: the grid
|
|
436
|
+
* silently collapsed to one column at widths that clearly had room for two.
|
|
437
|
+
* The extra pixel buys slack so the arithmetic resolves the same way at every
|
|
438
|
+
* fractional container width, and costs only 1px of minimum track width. */
|
|
439
|
+
.aq-mcp-zone--two-up {
|
|
440
|
+
grid-template-columns: repeat(auto-fit, minmax(max(240px, calc(50% - 13px)), 1fr));
|
|
441
|
+
column-gap: 24px;
|
|
442
|
+
}
|
|
443
|
+
/* A plain hairline between the fields the user must set and the ones the
|
|
444
|
+
connector already defaulted. Deliberately UNCAPTIONED: a heading here would
|
|
445
|
+
be the renderer naming a group the descriptor never described. */
|
|
446
|
+
.aq-mcp-zone__rule {
|
|
447
|
+
height: 1px;
|
|
448
|
+
margin: 26px 0 20px;
|
|
449
|
+
background: var(--ng-colors-border-secondary-alt, #f0f1f4);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.aq-mcp-section--dense .aq-mcp-section__footer {
|
|
453
|
+
align-items: center;
|
|
454
|
+
justify-content: space-between;
|
|
455
|
+
padding: 16px 0 0;
|
|
456
|
+
margin-top: 18px;
|
|
457
|
+
background: transparent;
|
|
458
|
+
border-top: 1px solid var(--ng-colors-border-secondary-alt, #f0f1f4);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* ── dense field cell ── */
|
|
462
|
+
/* Overrides `.aq-mcp-field`'s two-column row: one column, label above the
|
|
463
|
+
control, no row separator (the zone gap does that job). */
|
|
464
|
+
.aq-mcp-field--dense {
|
|
465
|
+
display: block;
|
|
466
|
+
padding: 0;
|
|
467
|
+
border-top: 0;
|
|
468
|
+
min-width: 0;
|
|
469
|
+
}
|
|
470
|
+
/* `datatype: "none"` (buttons, reports, tables) renders control-only and
|
|
471
|
+
spans the grid — see `renderDense`. */
|
|
472
|
+
.aq-mcp-field--dense:has(> .aq-mcp-field__control--full) {
|
|
473
|
+
grid-column: 1 / -1;
|
|
474
|
+
}
|
|
475
|
+
.aq-mcp-field--dense .aq-mcp-field__label {
|
|
476
|
+
display: flex;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 8px;
|
|
479
|
+
margin-bottom: 6px;
|
|
480
|
+
font-size: 13px;
|
|
481
|
+
font-weight: 600;
|
|
482
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
483
|
+
}
|
|
484
|
+
.aq-mcp-field__label-text {
|
|
485
|
+
overflow: hidden;
|
|
486
|
+
text-overflow: ellipsis;
|
|
487
|
+
white-space: nowrap;
|
|
488
|
+
}
|
|
489
|
+
/* "Needs a value" — shown only while the requirement is outstanding (see
|
|
490
|
+
renderRequiredMark), so it reads as a to-do rather than as decoration.
|
|
491
|
+
Amber, not red: nothing is wrong yet, it simply is not done. */
|
|
492
|
+
.aq-mcp-field--dense .aq-mcp-field__req {
|
|
493
|
+
flex: 0 0 auto;
|
|
494
|
+
margin-left: 0;
|
|
495
|
+
padding: 2px 8px;
|
|
496
|
+
border: 1px solid var(--ng-color-warning-300, #fec84b);
|
|
497
|
+
border-radius: var(--ng-r-full, 999px);
|
|
498
|
+
background: var(--ng-color-warning-50, #fffaeb);
|
|
499
|
+
color: var(--ng-color-warning-700, #b54708);
|
|
500
|
+
font-size: 11px;
|
|
501
|
+
font-weight: 600;
|
|
502
|
+
letter-spacing: 0.01em;
|
|
503
|
+
}
|
|
504
|
+
/* The pass mark on a field that satisfies its own `validation` rules. */
|
|
505
|
+
.aq-mcp-field__valid {
|
|
506
|
+
color: var(--ng-color-success-600, #079455);
|
|
507
|
+
}
|
|
508
|
+
/* Help sits UNDER the control as hint text (not in a tooltip): always
|
|
509
|
+
visible, no hover or tap needed, and it reflows with the cell instead of
|
|
510
|
+
floating over the card. Same `.aq-mcp-field__help` block the other layouts
|
|
511
|
+
render, so its "View more/less" truncation behaves identically here. */
|
|
512
|
+
.aq-mcp-field--dense .aq-mcp-field__help {
|
|
513
|
+
margin-top: 6px;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/* ── dense toggle row ── */
|
|
517
|
+
/* A boolean is its own labelled block rather than a label-above-control cell:
|
|
518
|
+
the control is small enough that stacking a label over it wastes the row,
|
|
519
|
+
and the description belongs inside the block, not hanging beneath it. */
|
|
520
|
+
.aq-mcp-field--dense[data-toggle] {
|
|
521
|
+
grid-column: 1 / -1;
|
|
522
|
+
}
|
|
523
|
+
.aq-mcp-field--dense[data-toggle] .aq-mcp-field__toggle {
|
|
524
|
+
display: flex;
|
|
525
|
+
align-items: flex-start;
|
|
526
|
+
gap: 16px;
|
|
527
|
+
padding: 14px 16px;
|
|
528
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
529
|
+
border-radius: 10px;
|
|
530
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
531
|
+
}
|
|
532
|
+
.aq-mcp-field__toggle-text {
|
|
533
|
+
display: flex;
|
|
534
|
+
flex-direction: column;
|
|
535
|
+
gap: 3px;
|
|
536
|
+
flex: 1 1 auto;
|
|
537
|
+
min-width: 0;
|
|
538
|
+
}
|
|
539
|
+
.aq-mcp-field--dense[data-toggle] .aq-mcp-field__label-text {
|
|
540
|
+
font-size: 13px;
|
|
541
|
+
font-weight: 600;
|
|
542
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
543
|
+
white-space: normal;
|
|
544
|
+
}
|
|
545
|
+
.aq-mcp-field__toggle-help {
|
|
546
|
+
font-size: 12.5px;
|
|
547
|
+
line-height: 1.5;
|
|
548
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
549
|
+
}
|
|
550
|
+
.aq-mcp-field--dense[data-toggle] .aq-mcp-field__control {
|
|
551
|
+
flex: 0 0 auto;
|
|
552
|
+
padding-top: 2px;
|
|
553
|
+
}
|
|
554
|
+
.aq-mcp-field--dense[data-toggle][data-on] .aq-mcp-field__toggle {
|
|
555
|
+
border-color: var(--ng-colors-border-brand, #b2ccff);
|
|
556
|
+
background: var(--ng-colors-bg-brand-primary, #eff4ff);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* `file` control */
|
|
560
|
+
nile-file-preview {
|
|
561
|
+
display: block;
|
|
562
|
+
margin-top: 8px;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/* `test-connection-report` control */
|
|
566
|
+
.aq-mcp-report__meta {
|
|
567
|
+
margin: 0 0 10px;
|
|
568
|
+
font-size: 13px;
|
|
569
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
570
|
+
}
|
|
571
|
+
.aq-mcp-report__checks {
|
|
572
|
+
margin-top: 16px;
|
|
573
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
574
|
+
border-radius: 12px;
|
|
575
|
+
overflow: hidden;
|
|
576
|
+
}
|
|
577
|
+
.aq-mcp-check {
|
|
578
|
+
border-top: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
579
|
+
}
|
|
580
|
+
.aq-mcp-check:first-child {
|
|
581
|
+
border-top: 0;
|
|
582
|
+
}
|
|
583
|
+
/* A plain check (no accordion): the row itself carries the padding. */
|
|
584
|
+
div.aq-mcp-check > .aq-mcp-check__row {
|
|
585
|
+
padding: 14px 16px;
|
|
586
|
+
}
|
|
587
|
+
/* A failed+mitigation check is a native <details>/<summary> — same row
|
|
588
|
+
markup/padding as the plain case, just with a trailing chevron and a
|
|
589
|
+
collapsible panel, so nothing shifts out of alignment between rows. */
|
|
590
|
+
details.aq-mcp-check > summary.aq-mcp-check__row {
|
|
591
|
+
padding: 14px 16px;
|
|
592
|
+
cursor: pointer;
|
|
593
|
+
list-style: none;
|
|
594
|
+
}
|
|
595
|
+
details.aq-mcp-check > summary::-webkit-details-marker {
|
|
596
|
+
display: none;
|
|
597
|
+
}
|
|
598
|
+
.aq-mcp-check__chevron {
|
|
599
|
+
flex: 0 0 auto;
|
|
600
|
+
margin-top: 1px;
|
|
601
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
602
|
+
transition: transform 0.15s ease;
|
|
603
|
+
}
|
|
604
|
+
details[open] > summary .aq-mcp-check__chevron {
|
|
605
|
+
transform: rotate(180deg);
|
|
606
|
+
}
|
|
607
|
+
details.aq-mcp-check > .aq-mcp-check__fix {
|
|
608
|
+
margin: 0 16px 14px 16px;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.aq-mcp-check__row {
|
|
612
|
+
display: flex;
|
|
613
|
+
align-items: flex-start;
|
|
614
|
+
gap: 12px;
|
|
615
|
+
width: 100%;
|
|
616
|
+
}
|
|
617
|
+
.aq-mcp-check__icon {
|
|
618
|
+
flex: 0 0 auto;
|
|
619
|
+
margin-top: 1px;
|
|
620
|
+
}
|
|
621
|
+
.aq-mcp-check--passed .aq-mcp-check__icon {
|
|
622
|
+
color: var(--ng-color-success-500, #17b26a);
|
|
623
|
+
}
|
|
624
|
+
.aq-mcp-check--failed .aq-mcp-check__icon {
|
|
625
|
+
color: var(--ng-color-error-500, #d92d20);
|
|
626
|
+
}
|
|
627
|
+
.aq-mcp-check--skipped .aq-mcp-check__icon {
|
|
628
|
+
color: var(--ng-colors-text-tertiary-600, #98a2b3);
|
|
629
|
+
}
|
|
630
|
+
.aq-mcp-check__body {
|
|
631
|
+
flex: 1 1 auto;
|
|
632
|
+
min-width: 0;
|
|
633
|
+
}
|
|
634
|
+
.aq-mcp-check__name {
|
|
635
|
+
font-size: 14px;
|
|
636
|
+
font-weight: 600;
|
|
637
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
638
|
+
}
|
|
639
|
+
.aq-mcp-check__message {
|
|
640
|
+
margin-top: 2px;
|
|
641
|
+
font-size: 13px;
|
|
642
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
643
|
+
}
|
|
644
|
+
.aq-mcp-check--failed .aq-mcp-check__message {
|
|
645
|
+
color: var(--ng-color-error-500, #d92d20);
|
|
646
|
+
}
|
|
647
|
+
.aq-mcp-check__endpoint {
|
|
648
|
+
flex: 0 0 auto;
|
|
649
|
+
padding-top: 2px;
|
|
650
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
651
|
+
font-size: 12px;
|
|
652
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
653
|
+
white-space: nowrap;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/* The "How to fix" panel — a distinct card inside the accordion's content slot. */
|
|
657
|
+
.aq-mcp-check__fix {
|
|
658
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
659
|
+
border-radius: 8px;
|
|
660
|
+
padding: 12px 14px;
|
|
661
|
+
}
|
|
662
|
+
.aq-mcp-check__fix-label {
|
|
663
|
+
font-size: 11px;
|
|
664
|
+
font-weight: 700;
|
|
665
|
+
text-transform: uppercase;
|
|
666
|
+
letter-spacing: 0.04em;
|
|
667
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
668
|
+
margin-bottom: 6px;
|
|
669
|
+
}
|
|
670
|
+
.aq-mcp-check__fix-body {
|
|
671
|
+
font-size: 13px;
|
|
672
|
+
line-height: 1.5;
|
|
673
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/* `properties-table`'s own card header (title/subtitle + action toolbar) — this
|
|
677
|
+
control is a `FULL_WIDTH_CONTROLS` entry (aq-mcp-field.ts), so `.aq-mcp-field`'s
|
|
678
|
+
usual two-column grid collapses to one column for its row via this class. */
|
|
679
|
+
.aq-mcp-field__control--full {
|
|
680
|
+
grid-column: 1 / -1;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/* `permissions-report` control — a validation banner + "N Granted" stat + an
|
|
684
|
+
All/Success filter + a Resource Type/Permission Type/Access table, matching
|
|
685
|
+
the live reference's own Credentials-tab Test Connection result. The filter
|
|
686
|
+
is pure CSS: the two `.aq-mcp-permissions__filter-input` radios are visually
|
|
687
|
+
hidden but keep native tab/keyboard/click behavior; `:has()` lets the
|
|
688
|
+
ancestor `.aq-mcp-permissions__report` react to which one is checked without
|
|
689
|
+
any per-instance selector (`:nth-of-type(2)` = the "Success" radio, always
|
|
690
|
+
second) — no Lit reactive state needed for the toggle. */
|
|
691
|
+
.aq-mcp-permissions__filter-input {
|
|
692
|
+
position: absolute;
|
|
693
|
+
opacity: 0;
|
|
694
|
+
width: 1px;
|
|
695
|
+
height: 1px;
|
|
696
|
+
}
|
|
697
|
+
.aq-mcp-permissions__report {
|
|
698
|
+
margin-top: 16px;
|
|
699
|
+
}
|
|
700
|
+
.aq-mcp-permissions__report-title {
|
|
701
|
+
font-size: 15px;
|
|
702
|
+
font-weight: 700;
|
|
703
|
+
color: var(--ng-colors-text-primary-900, #101828);
|
|
704
|
+
margin-bottom: 12px;
|
|
705
|
+
}
|
|
706
|
+
.aq-mcp-permissions__toolbar {
|
|
707
|
+
display: flex;
|
|
708
|
+
align-items: center;
|
|
709
|
+
justify-content: space-between;
|
|
710
|
+
margin-bottom: 12px;
|
|
711
|
+
}
|
|
712
|
+
.aq-mcp-permissions__stat {
|
|
713
|
+
display: flex;
|
|
714
|
+
align-items: center;
|
|
715
|
+
gap: 8px;
|
|
716
|
+
padding-left: 12px;
|
|
717
|
+
border-left: 3px solid var(--ng-color-success-500, #12b76a);
|
|
718
|
+
}
|
|
719
|
+
.aq-mcp-permissions__stat-count {
|
|
720
|
+
font-size: 15px;
|
|
721
|
+
font-weight: 700;
|
|
722
|
+
color: var(--ng-colors-text-primary-900, #101828);
|
|
723
|
+
}
|
|
724
|
+
.aq-mcp-permissions__stat-label {
|
|
725
|
+
font-size: 12px;
|
|
726
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
727
|
+
}
|
|
728
|
+
.aq-mcp-permissions__filter-labels {
|
|
729
|
+
display: flex;
|
|
730
|
+
padding: 2px;
|
|
731
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
732
|
+
border-radius: 8px;
|
|
733
|
+
}
|
|
734
|
+
.aq-mcp-permissions__filter-label {
|
|
735
|
+
padding: 5px 14px;
|
|
736
|
+
font-size: 13px;
|
|
737
|
+
font-weight: 600;
|
|
738
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
739
|
+
border-radius: 6px;
|
|
740
|
+
cursor: pointer;
|
|
741
|
+
}
|
|
742
|
+
.aq-mcp-permissions__filter-input:checked + .aq-mcp-permissions__filter-label {
|
|
743
|
+
background: var(--ng-colors-bg-primary, #fff);
|
|
744
|
+
color: var(--ng-componentcolors-utility-brand-600, #155eef);
|
|
745
|
+
box-shadow: 0 1px 2px rgb(16 24 40 / 0.05);
|
|
746
|
+
}
|
|
747
|
+
.aq-mcp-permissions__filter-input:nth-of-type(2):checked ~ .aq-mcp-permissions__table
|
|
748
|
+
.aq-mcp-permissions__row[data-access]:not([data-access='Granted']) {
|
|
749
|
+
display: none;
|
|
750
|
+
}
|
|
751
|
+
.aq-mcp-table-card__header {
|
|
752
|
+
display: flex;
|
|
753
|
+
align-items: flex-start;
|
|
754
|
+
justify-content: space-between;
|
|
755
|
+
gap: 16px;
|
|
756
|
+
margin-bottom: 16px;
|
|
757
|
+
}
|
|
758
|
+
.aq-mcp-table-card__title {
|
|
759
|
+
font-size: 14px;
|
|
760
|
+
font-weight: 600;
|
|
761
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
762
|
+
}
|
|
763
|
+
.aq-mcp-table-card__subtitle {
|
|
764
|
+
margin-top: 4px;
|
|
765
|
+
font-size: 13px;
|
|
766
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
767
|
+
}
|
|
768
|
+
.aq-mcp-table-card__actions {
|
|
769
|
+
display: flex;
|
|
770
|
+
align-items: center;
|
|
771
|
+
gap: 8px;
|
|
772
|
+
flex-shrink: 0;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/* `properties-table` control — a plain semantic <table>, not a Nile component
|
|
776
|
+
(Nile has no read-only data-table primitive this simple use case needs). */
|
|
777
|
+
.aq-mcp-table {
|
|
778
|
+
width: 100%;
|
|
779
|
+
border: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
780
|
+
border-radius: 12px;
|
|
781
|
+
border-collapse: collapse;
|
|
782
|
+
overflow: hidden;
|
|
783
|
+
font-size: 13px;
|
|
784
|
+
}
|
|
785
|
+
.aq-mcp-table th,
|
|
786
|
+
.aq-mcp-table td {
|
|
787
|
+
padding: 12px 16px;
|
|
788
|
+
text-align: left;
|
|
789
|
+
border-top: 1px solid var(--ng-colors-border-secondary, #e4e7ec);
|
|
790
|
+
}
|
|
791
|
+
.aq-mcp-table thead th {
|
|
792
|
+
border-top: 0;
|
|
793
|
+
background: var(--ng-colors-bg-secondary, #f9fafb);
|
|
794
|
+
font-size: 11px;
|
|
795
|
+
font-weight: 700;
|
|
796
|
+
text-transform: uppercase;
|
|
797
|
+
letter-spacing: 0.04em;
|
|
798
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
799
|
+
}
|
|
800
|
+
.aq-mcp-table__property {
|
|
801
|
+
font-weight: 600;
|
|
802
|
+
color: var(--ng-colors-text-secondary-700, #344054);
|
|
803
|
+
white-space: nowrap;
|
|
804
|
+
max-width: 200px;
|
|
805
|
+
overflow: hidden;
|
|
806
|
+
text-overflow: ellipsis;
|
|
807
|
+
}
|
|
808
|
+
.aq-mcp-table__value {
|
|
809
|
+
color: var(--ng-colors-text-tertiary-600, #667085);
|
|
810
|
+
overflow-wrap: anywhere;
|
|
811
|
+
}
|