@seed-ship/mcp-ui-solid 6.23.0 → 6.25.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 +167 -0
- package/README.md +154 -2
- package/dist/components/ActionGroupRenderer.cjs +6 -6
- package/dist/components/ActionGroupRenderer.cjs.map +1 -1
- package/dist/components/ActionGroupRenderer.js +6 -6
- package/dist/components/ActionGroupRenderer.js.map +1 -1
- package/dist/components/AutocompleteDropdown.cjs +6 -6
- package/dist/components/AutocompleteDropdown.cjs.map +1 -1
- package/dist/components/AutocompleteDropdown.js +6 -6
- package/dist/components/AutocompleteDropdown.js.map +1 -1
- package/dist/components/AutocompleteFormField.cjs +6 -5
- package/dist/components/AutocompleteFormField.cjs.map +1 -1
- package/dist/components/AutocompleteFormField.d.ts.map +1 -1
- package/dist/components/AutocompleteFormField.js +6 -5
- package/dist/components/AutocompleteFormField.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +406 -70
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +407 -71
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ChatPrompt.cjs +5 -5
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.js +5 -5
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/ComponentToolbar.cjs +5 -5
- package/dist/components/ComponentToolbar.cjs.map +1 -1
- package/dist/components/ComponentToolbar.js +5 -5
- package/dist/components/ComponentToolbar.js.map +1 -1
- package/dist/components/DegradedFallback.cjs +35 -3
- package/dist/components/DegradedFallback.cjs.map +1 -1
- package/dist/components/DegradedFallback.d.ts +7 -0
- package/dist/components/DegradedFallback.d.ts.map +1 -1
- package/dist/components/DegradedFallback.js +35 -3
- package/dist/components/DegradedFallback.js.map +1 -1
- package/dist/components/ExpandableWrapper.cjs +10 -7
- package/dist/components/ExpandableWrapper.cjs.map +1 -1
- package/dist/components/ExpandableWrapper.d.ts.map +1 -1
- package/dist/components/ExpandableWrapper.js +10 -7
- package/dist/components/ExpandableWrapper.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +13 -12
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +13 -12
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +1 -1
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.js +1 -1
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/GhostText.cjs +2 -2
- package/dist/components/GhostText.cjs.map +1 -1
- package/dist/components/GhostText.js +2 -2
- package/dist/components/GhostText.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +100 -29
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +100 -29
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/MissingValue.cjs +43 -0
- package/dist/components/MissingValue.cjs.map +1 -0
- package/dist/components/MissingValue.d.ts +27 -0
- package/dist/components/MissingValue.d.ts.map +1 -0
- package/dist/components/MissingValue.js +43 -0
- package/dist/components/MissingValue.js.map +1 -0
- package/dist/components/ModalRenderer.cjs +39 -31
- package/dist/components/ModalRenderer.cjs.map +1 -1
- package/dist/components/ModalRenderer.d.ts.map +1 -1
- package/dist/components/ModalRenderer.js +40 -32
- package/dist/components/ModalRenderer.js.map +1 -1
- package/dist/components/PortalDropdownMenu.cjs +6 -3
- package/dist/components/PortalDropdownMenu.cjs.map +1 -1
- package/dist/components/PortalDropdownMenu.d.ts.map +1 -1
- package/dist/components/PortalDropdownMenu.js +7 -4
- package/dist/components/PortalDropdownMenu.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +38 -44
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +38 -44
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +255 -217
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +255 -217
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/chart-data-table.cjs +30 -5
- package/dist/components/chart-data-table.cjs.map +1 -1
- package/dist/components/chart-data-table.d.ts +18 -1
- package/dist/components/chart-data-table.d.ts.map +1 -1
- package/dist/components/chart-data-table.js +30 -5
- package/dist/components/chart-data-table.js.map +1 -1
- package/dist/components/chart-missing-plugin.cjs +194 -0
- package/dist/components/chart-missing-plugin.cjs.map +1 -0
- package/dist/components/chart-missing-plugin.d.ts +129 -0
- package/dist/components/chart-missing-plugin.d.ts.map +1 -0
- package/dist/components/chart-missing-plugin.js +194 -0
- package/dist/components/chart-missing-plugin.js.map +1 -0
- package/dist/context/MCPUIStringsContext.cjs +12 -1
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +62 -0
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +12 -1
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/services/component-registry.cjs +9 -2
- package/dist/services/component-registry.cjs.map +1 -1
- package/dist/services/component-registry.d.ts.map +1 -1
- package/dist/services/component-registry.js +9 -2
- package/dist/services/component-registry.js.map +1 -1
- package/dist/services/validation.cjs +31 -8
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +31 -8
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +14 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/degraded-projections.cjs +19 -3
- package/dist/utils/degraded-projections.cjs.map +1 -1
- package/dist/utils/degraded-projections.d.ts +22 -2
- package/dist/utils/degraded-projections.d.ts.map +1 -1
- package/dist/utils/degraded-projections.js +19 -3
- package/dist/utils/degraded-projections.js.map +1 -1
- package/dist/utils/math-markdown.cjs +1 -1
- package/dist/utils/math-markdown.cjs.map +1 -1
- package/dist/utils/math-markdown.js +1 -1
- package/dist/utils/math-markdown.js.map +1 -1
- package/dist/utils/missing-value.cjs +60 -0
- package/dist/utils/missing-value.cjs.map +1 -0
- package/dist/utils/missing-value.d.ts +79 -0
- package/dist/utils/missing-value.d.ts.map +1 -0
- package/dist/utils/missing-value.js +60 -0
- package/dist/utils/missing-value.js.map +1 -0
- package/dist/utils/theme.cjs +91 -0
- package/dist/utils/theme.cjs.map +1 -0
- package/dist/utils/theme.d.ts +11 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +91 -0
- package/dist/utils/theme.js.map +1 -0
- package/docs/SECURITY-DEPENDENCIES.md +81 -0
- package/docs/THEMING.md +205 -0
- package/package.json +7 -5
- package/src/components/ActionGroupRenderer.tsx +6 -6
- package/src/components/AutocompleteDropdown.tsx +17 -17
- package/src/components/AutocompleteFormField.tsx +10 -9
- package/src/components/ChartJSRenderer.tsx +609 -212
- package/src/components/ChatPrompt.tsx +16 -16
- package/src/components/ComponentToolbar.tsx +5 -5
- package/src/components/DegradedFallback.tsx +33 -11
- package/src/components/ExpandableWrapper.tsx +15 -11
- package/src/components/FormFieldRenderer.tsx +52 -51
- package/src/components/FormRenderer.tsx +12 -12
- package/src/components/GenerativeUIErrorBoundary.tsx +6 -6
- package/src/components/GhostText.tsx +7 -7
- package/src/components/GraphRenderer.tsx +83 -67
- package/src/components/MissingValue.tsx +61 -0
- package/src/components/ModalRenderer.tsx +11 -5
- package/src/components/PortalDropdownMenu.tsx +6 -2
- package/src/components/ScratchpadPanel.tsx +144 -141
- package/src/components/UIResourceRenderer.tsx +143 -110
- package/src/components/chart-data-table.ts +50 -6
- package/src/components/chart-missing-plugin.ts +336 -0
- package/src/context/MCPUIStringsContext.tsx +76 -0
- package/src/services/component-registry.ts +10 -2
- package/src/services/validation.ts +44 -9
- package/src/styles/autocomplete.css +53 -53
- package/src/types/index.ts +13 -1
- package/src/utils/degraded-projections.ts +44 -4
- package/src/utils/math-markdown.ts +1 -1
- package/src/utils/missing-value.ts +127 -0
- package/src/utils/theme.ts +101 -0
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
.mcp-ghost-text {
|
|
40
|
-
color: #9ca3af;
|
|
40
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
41
41
|
opacity: 0.7;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
top: 50%;
|
|
48
48
|
transform: translateY(-50%);
|
|
49
49
|
font-size: 0.75rem;
|
|
50
|
-
color: #6b7280;
|
|
51
|
-
background-color: rgba(255, 255, 255, 0.95);
|
|
50
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
51
|
+
background-color: var(--mcp-ui-surface, rgba(255, 255, 255, 0.95));
|
|
52
52
|
padding: 2px 8px;
|
|
53
53
|
border-radius: 4px;
|
|
54
|
-
border: 1px solid #e5e7eb;
|
|
54
|
+
border: 1px solid var(--mcp-ui-border, #e5e7eb);
|
|
55
55
|
pointer-events: none;
|
|
56
56
|
animation: mcp-hint-fade-in 150ms ease;
|
|
57
57
|
}
|
|
@@ -86,10 +86,10 @@
|
|
|
86
86
|
left: 0;
|
|
87
87
|
right: 0;
|
|
88
88
|
z-index: 50;
|
|
89
|
-
background-color: #ffffff;
|
|
90
|
-
border: 1px solid #e5e7eb;
|
|
89
|
+
background-color: var(--mcp-ui-surface, #ffffff);
|
|
90
|
+
border: 1px solid var(--mcp-ui-border, #e5e7eb);
|
|
91
91
|
border-radius: 6px;
|
|
92
|
-
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
92
|
+
box-shadow: var(--mcp-ui-shadow, 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06));
|
|
93
93
|
overflow: hidden;
|
|
94
94
|
animation: mcp-dropdown-enter 150ms ease;
|
|
95
95
|
}
|
|
@@ -120,11 +120,11 @@
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
.mcp-autocomplete-option:hover {
|
|
123
|
-
background-color: #f3f4f6;
|
|
123
|
+
background-color: var(--mcp-ui-surface-hover, #f3f4f6);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
.mcp-autocomplete-option-selected {
|
|
127
|
-
background-color: #eff6ff !important;
|
|
127
|
+
background-color: var(--mcp-ui-accent-soft, #eff6ff) !important;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
.mcp-autocomplete-option-disabled {
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
.mcp-autocomplete-option-label {
|
|
160
160
|
display: block;
|
|
161
161
|
font-size: 0.875rem;
|
|
162
|
-
color: #374151;
|
|
162
|
+
color: var(--mcp-ui-fg, #374151);
|
|
163
163
|
white-space: nowrap;
|
|
164
164
|
overflow: hidden;
|
|
165
165
|
text-overflow: ellipsis;
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
.mcp-autocomplete-option-description {
|
|
169
169
|
display: block;
|
|
170
170
|
font-size: 0.75rem;
|
|
171
|
-
color: #6b7280;
|
|
171
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
172
172
|
white-space: nowrap;
|
|
173
173
|
overflow: hidden;
|
|
174
174
|
text-overflow: ellipsis;
|
|
@@ -177,14 +177,14 @@
|
|
|
177
177
|
|
|
178
178
|
.mcp-autocomplete-highlight {
|
|
179
179
|
font-weight: 600;
|
|
180
|
-
color: #1d4ed8;
|
|
180
|
+
color: var(--mcp-ui-accent, #1d4ed8);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
.mcp-autocomplete-loading,
|
|
184
184
|
.mcp-autocomplete-empty {
|
|
185
185
|
padding: 12px 16px;
|
|
186
186
|
font-size: 0.875rem;
|
|
187
|
-
color: #6b7280;
|
|
187
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
.mcp-autocomplete-loading {
|
|
@@ -199,10 +199,10 @@
|
|
|
199
199
|
|
|
200
200
|
.mcp-autocomplete-footer {
|
|
201
201
|
padding: 6px 12px;
|
|
202
|
-
border-top: 1px solid #e5e7eb;
|
|
203
|
-
background-color: #f9fafb;
|
|
202
|
+
border-top: 1px solid var(--mcp-ui-border, #e5e7eb);
|
|
203
|
+
background-color: var(--mcp-ui-surface-muted, #f9fafb);
|
|
204
204
|
font-size: 0.75rem;
|
|
205
|
-
color: #6b7280;
|
|
205
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
/* =============================================================================
|
|
@@ -211,107 +211,107 @@
|
|
|
211
211
|
|
|
212
212
|
@media (prefers-color-scheme: dark) {
|
|
213
213
|
.mcp-ghost-text {
|
|
214
|
-
color: #6b7280;
|
|
214
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
.mcp-ghost-text-hint {
|
|
218
|
-
background-color: rgba(31, 41, 55, 0.95);
|
|
219
|
-
border-color: #374151;
|
|
220
|
-
color: #9ca3af;
|
|
218
|
+
background-color: var(--mcp-ui-surface, rgba(31, 41, 55, 0.95));
|
|
219
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
220
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
.mcp-autocomplete-dropdown {
|
|
224
|
-
background-color: #1f2937;
|
|
225
|
-
border-color: #374151;
|
|
224
|
+
background-color: var(--mcp-ui-surface, #1f2937);
|
|
225
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
.mcp-autocomplete-option:hover {
|
|
229
|
-
background-color: #374151;
|
|
229
|
+
background-color: var(--mcp-ui-surface-hover, #374151);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
.mcp-autocomplete-option-selected {
|
|
233
|
-
background-color: #1e3a5f !important;
|
|
233
|
+
background-color: var(--mcp-ui-accent-soft, #1e3a5f) !important;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
.mcp-autocomplete-option-label {
|
|
237
|
-
color: #e5e7eb;
|
|
237
|
+
color: var(--mcp-ui-fg, #e5e7eb);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
.mcp-autocomplete-option-description {
|
|
241
|
-
color: #9ca3af;
|
|
241
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
.mcp-autocomplete-highlight {
|
|
245
|
-
color: #60a5fa;
|
|
245
|
+
color: var(--mcp-ui-accent, #60a5fa);
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
.mcp-autocomplete-loading,
|
|
249
249
|
.mcp-autocomplete-empty {
|
|
250
|
-
color: #9ca3af;
|
|
250
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
.mcp-autocomplete-footer {
|
|
254
|
-
background-color: #111827;
|
|
255
|
-
border-color: #374151;
|
|
256
|
-
color: #9ca3af;
|
|
254
|
+
background-color: var(--mcp-ui-surface-muted, #111827);
|
|
255
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
256
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
.mcp-autocomplete-footer kbd {
|
|
260
|
-
background-color: #374151;
|
|
261
|
-
color: #d1d5db;
|
|
260
|
+
background-color: var(--mcp-ui-surface-hover, #374151);
|
|
261
|
+
color: var(--mcp-ui-fg, #d1d5db);
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
/* Explicit dark mode class support */
|
|
266
266
|
.dark .mcp-ghost-text {
|
|
267
|
-
color: #6b7280;
|
|
267
|
+
color: var(--mcp-ui-fg-muted, #6b7280);
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
.dark .mcp-ghost-text-hint {
|
|
271
|
-
background-color: rgba(31, 41, 55, 0.95);
|
|
272
|
-
border-color: #374151;
|
|
273
|
-
color: #9ca3af;
|
|
271
|
+
background-color: var(--mcp-ui-surface, rgba(31, 41, 55, 0.95));
|
|
272
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
273
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
.dark .mcp-autocomplete-dropdown {
|
|
277
|
-
background-color: #1f2937;
|
|
278
|
-
border-color: #374151;
|
|
277
|
+
background-color: var(--mcp-ui-surface, #1f2937);
|
|
278
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
.dark .mcp-autocomplete-option:hover {
|
|
282
|
-
background-color: #374151;
|
|
282
|
+
background-color: var(--mcp-ui-surface-hover, #374151);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
.dark .mcp-autocomplete-option-selected {
|
|
286
|
-
background-color: #1e3a5f !important;
|
|
286
|
+
background-color: var(--mcp-ui-accent-soft, #1e3a5f) !important;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
.dark .mcp-autocomplete-option-label {
|
|
290
|
-
color: #e5e7eb;
|
|
290
|
+
color: var(--mcp-ui-fg, #e5e7eb);
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
.dark .mcp-autocomplete-option-description {
|
|
294
|
-
color: #9ca3af;
|
|
294
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
.dark .mcp-autocomplete-highlight {
|
|
298
|
-
color: #60a5fa;
|
|
298
|
+
color: var(--mcp-ui-accent, #60a5fa);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
.dark .mcp-autocomplete-loading,
|
|
302
302
|
.dark .mcp-autocomplete-empty {
|
|
303
|
-
color: #9ca3af;
|
|
303
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
.dark .mcp-autocomplete-footer {
|
|
307
|
-
background-color: #111827;
|
|
308
|
-
border-color: #374151;
|
|
309
|
-
color: #9ca3af;
|
|
307
|
+
background-color: var(--mcp-ui-surface-muted, #111827);
|
|
308
|
+
border-color: var(--mcp-ui-border, #374151);
|
|
309
|
+
color: var(--mcp-ui-fg-subtle, #9ca3af);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
.dark .mcp-autocomplete-footer kbd {
|
|
313
|
-
background-color: #374151;
|
|
314
|
-
color: #d1d5db;
|
|
313
|
+
background-color: var(--mcp-ui-surface-hover, #374151);
|
|
314
|
+
color: var(--mcp-ui-fg, #d1d5db);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
/* =============================================================================
|
|
@@ -327,12 +327,12 @@
|
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
.mcp-autocomplete-options::-webkit-scrollbar-thumb {
|
|
330
|
-
background-color: #d1d5db;
|
|
330
|
+
background-color: var(--mcp-ui-surface-hover, #d1d5db);
|
|
331
331
|
border-radius: 3px;
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
.dark .mcp-autocomplete-options::-webkit-scrollbar-thumb {
|
|
335
|
-
background-color: #4b5563;
|
|
335
|
+
background-color: var(--mcp-ui-surface-hover, #4b5563);
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
/* =============================================================================
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
|
|
342
342
|
/* Focus styles */
|
|
343
343
|
.mcp-autocomplete-option:focus {
|
|
344
|
-
outline: 2px solid #3b82f6;
|
|
344
|
+
outline: 2px solid var(--mcp-ui-focus, #3b82f6);
|
|
345
345
|
outline-offset: -2px;
|
|
346
346
|
}
|
|
347
347
|
|
package/src/types/index.ts
CHANGED
|
@@ -81,7 +81,13 @@ export interface ChartComponentParams {
|
|
|
81
81
|
labels: string[]
|
|
82
82
|
datasets: Array<{
|
|
83
83
|
label: string
|
|
84
|
-
|
|
84
|
+
/**
|
|
85
|
+
* `null` is an explicit missing value (v6.24.0): its label keeps its
|
|
86
|
+
* slot, a line breaks there, a bar shows a dashed outline — never a
|
|
87
|
+
* zero. Pie, doughnut and polar-area charts reject it, since they
|
|
88
|
+
* would draw it as a zero share.
|
|
89
|
+
*/
|
|
90
|
+
data: Array<number | null> | Array<{ x: string | number; y: number | null; r?: number }>
|
|
85
91
|
backgroundColor?: string | string[]
|
|
86
92
|
borderColor?: string | string[]
|
|
87
93
|
borderWidth?: number
|
|
@@ -135,6 +141,12 @@ export interface ChartComponentParams {
|
|
|
135
141
|
* Custom CSS class (Sprint 7)
|
|
136
142
|
*/
|
|
137
143
|
className?: string
|
|
144
|
+
/**
|
|
145
|
+
* Unit of every value in the chart (`'mm'`, `'km/h'`), shown as the value
|
|
146
|
+
* axis title (unless `options.scales` already sets one), after each tooltip
|
|
147
|
+
* value, and in the data-view column headers (v6.24.0). One unit per chart.
|
|
148
|
+
*/
|
|
149
|
+
unit?: string
|
|
138
150
|
}
|
|
139
151
|
|
|
140
152
|
/**
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { formatMCPUIString } from './format-string';
|
|
15
|
+
import { isMissingChartValue } from './missing-value';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Column headers and series names of the degraded tables.
|
|
@@ -46,10 +47,17 @@ export interface DegradedProjectionLabels {
|
|
|
46
47
|
feature: string;
|
|
47
48
|
/** Chart table — fallback dataset name. Template — `{n}`. */
|
|
48
49
|
series: string;
|
|
50
|
+
/**
|
|
51
|
+
* Chart table — a dataset column header followed by the chart's `unit`.
|
|
52
|
+
* Template — `{label}`, `{unit}`. Only applied when the chart has a unit.
|
|
53
|
+
* Optional so that a complete labels table written for 6.20.0–6.23.0 still
|
|
54
|
+
* type-checks. @since v6.24.0
|
|
55
|
+
*/
|
|
56
|
+
withUnit?: string;
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
/** English defaults for {@link DegradedProjectionLabels}. */
|
|
52
|
-
export const DEGRADED_PROJECTION_LABELS: DegradedProjectionLabels = {
|
|
60
|
+
export const DEGRADED_PROJECTION_LABELS: Required<DegradedProjectionLabels> = {
|
|
53
61
|
source: 'Source',
|
|
54
62
|
target: 'Target',
|
|
55
63
|
label: 'Label',
|
|
@@ -61,6 +69,7 @@ export const DEGRADED_PROJECTION_LABELS: DegradedProjectionLabels = {
|
|
|
61
69
|
marker: 'marker',
|
|
62
70
|
feature: 'feature',
|
|
63
71
|
series: 'Series {n}',
|
|
72
|
+
withUnit: '{label} ({unit})',
|
|
64
73
|
};
|
|
65
74
|
|
|
66
75
|
const withLabels = (labels?: Partial<DegradedProjectionLabels>): DegradedProjectionLabels => ({
|
|
@@ -73,6 +82,12 @@ export interface DegradedTable {
|
|
|
73
82
|
rows: Array<Array<string | number>>;
|
|
74
83
|
}
|
|
75
84
|
|
|
85
|
+
/** A degraded chart table: its cells, plus which of them are missing values. */
|
|
86
|
+
export interface DegradedChartTable extends DegradedTable {
|
|
87
|
+
/** Same shape as `rows`; `true` for a dataset entry that is missing. @since v6.24.0 */
|
|
88
|
+
missing: boolean[][];
|
|
89
|
+
}
|
|
90
|
+
|
|
76
91
|
const MAX_PROJECTED_ROWS = 200;
|
|
77
92
|
|
|
78
93
|
/** Compact a value to a single table cell string. */
|
|
@@ -188,25 +203,50 @@ export function mapToDegradedTable(params: {
|
|
|
188
203
|
* Chart → a series table: one row per label, one column per dataset. So a
|
|
189
204
|
* chart that can't draw still shows its numbers. Point/object data (scatter,
|
|
190
205
|
* bubble, time series) is stringified per cell.
|
|
206
|
+
*
|
|
207
|
+
* `missing` flags the cells whose dataset entry is a missing value (`null`
|
|
208
|
+
* or non-finite) so the table can mark them instead of showing an empty
|
|
209
|
+
* cell. A slot past the end of a shorter or empty dataset has no entry and is
|
|
210
|
+
* not flagged; a point object keeps its JSON text (where a `"y":null` reads
|
|
211
|
+
* as such) and is not flagged either. With a `unit`, dataset column headers
|
|
212
|
+
* become `labels.withUnit`.
|
|
191
213
|
*/
|
|
192
214
|
export function chartToDegradedTable(params: {
|
|
215
|
+
unit?: string;
|
|
193
216
|
data?: {
|
|
194
217
|
labels?: Array<string | number>;
|
|
195
218
|
datasets?: Array<{ label?: string; data?: unknown[] }>;
|
|
196
219
|
};
|
|
197
|
-
}, labels?: Partial<DegradedProjectionLabels>):
|
|
220
|
+
}, labels?: Partial<DegradedProjectionLabels>): DegradedChartTable {
|
|
198
221
|
const l = withLabels(labels);
|
|
222
|
+
const unit = typeof params.unit === 'string' && params.unit !== '' ? params.unit : undefined;
|
|
199
223
|
const datasets = params.data?.datasets ?? [];
|
|
200
224
|
const dataLabels = params.data?.labels ?? [];
|
|
201
225
|
const rowCount = Math.max(dataLabels.length, ...datasets.map((d) => d.data?.length ?? 0), 0);
|
|
202
226
|
|
|
203
227
|
const columns = [
|
|
204
228
|
'',
|
|
205
|
-
...datasets.map((d, i) =>
|
|
229
|
+
...datasets.map((d, i) => {
|
|
230
|
+
const name = d.label ?? formatMCPUIString(l.series, { n: i + 1 });
|
|
231
|
+
return unit === undefined
|
|
232
|
+
? name
|
|
233
|
+
: formatMCPUIString(l.withUnit ?? DEGRADED_PROJECTION_LABELS.withUnit, { label: name, unit });
|
|
234
|
+
}),
|
|
206
235
|
];
|
|
207
236
|
const rows: Array<Array<string | number>> = [];
|
|
237
|
+
const missing: boolean[][] = [];
|
|
208
238
|
for (let r = 0; r < Math.min(rowCount, MAX_PROJECTED_ROWS); r++) {
|
|
209
239
|
rows.push([cell(dataLabels[r] ?? r + 1), ...datasets.map((d) => cell(d.data?.[r]))]);
|
|
240
|
+
missing.push([
|
|
241
|
+
false,
|
|
242
|
+
...datasets.map((d) => {
|
|
243
|
+
// Past the end of a shorter or empty dataset there is no entry, so
|
|
244
|
+
// nothing to flag (the cell stays empty, as before 6.24.0).
|
|
245
|
+
if (r >= (d.data?.length ?? 0)) return false;
|
|
246
|
+
const entry = d.data?.[r];
|
|
247
|
+
return (entry === null || typeof entry !== 'object') && isMissingChartValue(entry);
|
|
248
|
+
}),
|
|
249
|
+
]);
|
|
210
250
|
}
|
|
211
|
-
return { columns, rows };
|
|
251
|
+
return { columns, rows, missing };
|
|
212
252
|
}
|
|
@@ -104,7 +104,7 @@ function isCurrencyLike(raw: string, tex: string, following: string): boolean {
|
|
|
104
104
|
return closerLooksLikeLaterOpener
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
const CELL_LINK_ATTRIBUTES = 'target="_blank" rel="noopener noreferrer" class="text-blue-600 dark:text-blue-400 hover:underline"'
|
|
107
|
+
const CELL_LINK_ATTRIBUTES = 'target="_blank" rel="noopener noreferrer" class="text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] hover:underline"'
|
|
108
108
|
|
|
109
109
|
function cellLinkExtension(): MarkedExtension {
|
|
110
110
|
return {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Missing values — one definition shared by tables, chart data views,
|
|
3
|
+
* degraded projections, chart validation and the chart renderer.
|
|
4
|
+
*
|
|
5
|
+
* @since v6.24.0
|
|
6
|
+
*
|
|
7
|
+
* A missing value is a value the payload says EXISTS but was not observed:
|
|
8
|
+
* `null` in a chart dataset (or as a point's `y`), `null` / `undefined` in a
|
|
9
|
+
* table cell. It is not a zero, and it is not the absence of a row or of a
|
|
10
|
+
* label: every view keeps its slot and marks it.
|
|
11
|
+
*
|
|
12
|
+
* Runtime-free on purpose (no `solid-js`): the pure projections in
|
|
13
|
+
* `chart-data-table.ts` and `degraded-projections.ts`, and `validation.ts`
|
|
14
|
+
* (published as the `/validation` subpath), import it.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** The glyph a table cell shows for a missing value — `renderCellValue`'s historical `-`. */
|
|
18
|
+
export const MISSING_VALUE_MARKER = '-'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Chart types that encode a value as a share of a whole (or, for polar area,
|
|
22
|
+
* as a wedge whose emptiness reads as zero). Chart.js parses a `null` share
|
|
23
|
+
* as `0`, so these types refuse missing values instead of drawing them.
|
|
24
|
+
*/
|
|
25
|
+
export const PART_TO_WHOLE_CHART_TYPES: ReadonlySet<string> = new Set([
|
|
26
|
+
'pie',
|
|
27
|
+
'doughnut',
|
|
28
|
+
'polarArea',
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether a raw TABLE cell value is displayed as {@link MISSING_VALUE_MARKER}.
|
|
33
|
+
*
|
|
34
|
+
* Mirrors the rules `renderCellValue` applies before any formatting — `null`,
|
|
35
|
+
* `undefined`, and a string that is empty or the word `undefined` once the
|
|
36
|
+
* backend's `"X – undefined"` debris is stripped — plus the literal marker
|
|
37
|
+
* itself (whitespace around it aside, which a table cell does not render),
|
|
38
|
+
* since it looks identical on screen and so must read identically.
|
|
39
|
+
*
|
|
40
|
+
* Objects are never missing here: `renderCellValue` renders them (link,
|
|
41
|
+
* name, or escaped JSON).
|
|
42
|
+
*/
|
|
43
|
+
export function isMissingCellValue(value: unknown): boolean {
|
|
44
|
+
if (value === null || value === undefined) return true
|
|
45
|
+
if (typeof value === 'object') return false
|
|
46
|
+
const cleaned = stripUndefinedDebris(String(value)).trim()
|
|
47
|
+
return cleaned === '' || cleaned === MISSING_VALUE_MARKER || cleaned.toLowerCase() === 'undefined'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Removes the `"Text – undefined"` / `"undefined – Text"` debris some
|
|
52
|
+
* backends concatenate. Shared with `renderCellValue` so both apply the very
|
|
53
|
+
* same cleanup.
|
|
54
|
+
*/
|
|
55
|
+
export function stripUndefinedDebris(value: string): string {
|
|
56
|
+
return value.replace(/\s*[–-]\s*undefined\s*$/gi, '').replace(/^undefined\s*[–-]\s*/gi, '')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether one CHART data entry is missing: `null` / `undefined`, a non-finite
|
|
61
|
+
* number (Chart.js parses those to `null` too), or a point whose `y` is.
|
|
62
|
+
*/
|
|
63
|
+
export function isMissingChartValue(value: unknown): boolean {
|
|
64
|
+
if (value === null || value === undefined) return true
|
|
65
|
+
if (typeof value === 'number') return !Number.isFinite(value)
|
|
66
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
67
|
+
const y = (value as { y?: unknown }).y
|
|
68
|
+
return y === null || y === undefined || (typeof y === 'number' && !Number.isFinite(y))
|
|
69
|
+
}
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* What a chart's missing values amount to.
|
|
75
|
+
*
|
|
76
|
+
* Only ENTRIES count: an explicit `null` (or non-finite number, or a point
|
|
77
|
+
* whose `y` is one). A dataset with no entry at all (`data: []`) is not
|
|
78
|
+
* "missing" — it is how 6.23.0 and earlier payloads said "nothing yet", e.g.
|
|
79
|
+
* while streaming, and it keeps rendering exactly as it did then.
|
|
80
|
+
*/
|
|
81
|
+
export interface ChartMissingSummary {
|
|
82
|
+
/** At least one entry of one dataset is missing. */
|
|
83
|
+
hasMissing: boolean
|
|
84
|
+
/** Per dataset, in order: it has entries and every one of them is missing. */
|
|
85
|
+
fullyMissing: boolean[]
|
|
86
|
+
/**
|
|
87
|
+
* Per dataset, in order: at least one observed value AND at least one
|
|
88
|
+
* missing entry — the series a reader actually sees broken.
|
|
89
|
+
*/
|
|
90
|
+
partiallyMissing: boolean[]
|
|
91
|
+
/** Something is missing and no dataset has a single observed value: nothing to plot. */
|
|
92
|
+
allMissing: boolean
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ChartDataLike {
|
|
96
|
+
data?: {
|
|
97
|
+
datasets?: Array<{ data?: unknown[] } | null | undefined>
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Summarises the missing values of a chart payload. Never throws on a malformed payload. */
|
|
102
|
+
export function summarizeChartMissing(params: ChartDataLike | null | undefined): ChartMissingSummary {
|
|
103
|
+
const datasets = Array.isArray(params?.data?.datasets) ? params.data.datasets : []
|
|
104
|
+
const fullyMissing: boolean[] = []
|
|
105
|
+
const partiallyMissing: boolean[] = []
|
|
106
|
+
let anyMissing = false
|
|
107
|
+
let anyObserved = false
|
|
108
|
+
for (const dataset of datasets) {
|
|
109
|
+
const data = Array.isArray(dataset?.data) ? dataset.data : []
|
|
110
|
+
let observed = 0
|
|
111
|
+
let missing = 0
|
|
112
|
+
for (const value of data) {
|
|
113
|
+
if (isMissingChartValue(value)) missing += 1
|
|
114
|
+
else observed += 1
|
|
115
|
+
}
|
|
116
|
+
fullyMissing.push(missing > 0 && observed === 0)
|
|
117
|
+
partiallyMissing.push(observed > 0 && missing > 0)
|
|
118
|
+
anyMissing ||= missing > 0
|
|
119
|
+
anyObserved ||= observed > 0
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
hasMissing: anyMissing,
|
|
123
|
+
fullyMissing,
|
|
124
|
+
partiallyMissing,
|
|
125
|
+
allMissing: anyMissing && !anyObserved,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createEffect, onCleanup } from 'solid-js'
|
|
2
|
+
|
|
3
|
+
const THEME_PREFIX = '--mcp-ui-'
|
|
4
|
+
|
|
5
|
+
/** Read only explicitly supplied host tokens; blank values retain engine defaults. */
|
|
6
|
+
export function readThemeTokens(
|
|
7
|
+
element: Element | undefined,
|
|
8
|
+
names: readonly string[],
|
|
9
|
+
): Record<string, string | undefined> {
|
|
10
|
+
const result: Record<string, string | undefined> = {}
|
|
11
|
+
const view = element?.ownerDocument.defaultView
|
|
12
|
+
const style = element && view ? view.getComputedStyle(element) : undefined
|
|
13
|
+
for (const name of names) result[name] = style?.getPropertyValue(name).trim() || undefined
|
|
14
|
+
return result
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Observe inherited theme changes, including moving a mounted renderer into a portal. */
|
|
18
|
+
export function observeTheme(element: HTMLElement, callback: () => void): () => void {
|
|
19
|
+
const view = element.ownerDocument.defaultView
|
|
20
|
+
if (!view?.MutationObserver) return () => {}
|
|
21
|
+
let stopped = false
|
|
22
|
+
let pending = false
|
|
23
|
+
const schedule = () => {
|
|
24
|
+
if (pending || stopped) return
|
|
25
|
+
pending = true
|
|
26
|
+
queueMicrotask(() => {
|
|
27
|
+
pending = false
|
|
28
|
+
if (!stopped) callback()
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
const observer = new view.MutationObserver((records) => {
|
|
32
|
+
if (records.some((record) => {
|
|
33
|
+
if (record.type === 'attributes') {
|
|
34
|
+
return record.target instanceof view.Element && record.target.contains(element)
|
|
35
|
+
}
|
|
36
|
+
return [...record.addedNodes, ...record.removedNodes].some(
|
|
37
|
+
(node) => node === element || node.contains(element),
|
|
38
|
+
)
|
|
39
|
+
})) schedule()
|
|
40
|
+
})
|
|
41
|
+
// Attribute names are deliberately not filtered: hosts may use any data-* selector.
|
|
42
|
+
observer.observe(element.ownerDocument.documentElement, {
|
|
43
|
+
attributes: true,
|
|
44
|
+
childList: true,
|
|
45
|
+
subtree: true,
|
|
46
|
+
})
|
|
47
|
+
return () => {
|
|
48
|
+
stopped = true
|
|
49
|
+
observer.disconnect()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A body portal cannot inherit a local host theme. Copy only our effective
|
|
55
|
+
* custom properties and dark state from its stationary anchor, and keep them
|
|
56
|
+
* synchronized for the lifetime of the Solid owner. Geometry stays unchanged.
|
|
57
|
+
*/
|
|
58
|
+
export function bindPortalTheme(portal: HTMLElement, source: () => HTMLElement | undefined): void {
|
|
59
|
+
createEffect(() => {
|
|
60
|
+
const anchor = source()
|
|
61
|
+
const view = anchor?.ownerDocument.defaultView
|
|
62
|
+
if (!anchor || !view) return
|
|
63
|
+
const copied = new Set<string>()
|
|
64
|
+
const sync = () => {
|
|
65
|
+
const style = view.getComputedStyle(anchor)
|
|
66
|
+
const inherited = portal.parentElement ? view.getComputedStyle(portal.parentElement) : undefined
|
|
67
|
+
const names = new Set(copied)
|
|
68
|
+
for (const computed of [style, inherited]) {
|
|
69
|
+
if (!computed) continue
|
|
70
|
+
for (let index = 0; index < computed.length; index++) {
|
|
71
|
+
const name = computed.item(index)
|
|
72
|
+
if (name.startsWith(THEME_PREFIX)) names.add(name)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const values = new Map<string, string>()
|
|
76
|
+
for (const name of names) {
|
|
77
|
+
const value = style.getPropertyValue(name).trim()
|
|
78
|
+
if (value) values.set(name, value)
|
|
79
|
+
// Empty setProperty removes a declaration. Explicitly block a body
|
|
80
|
+
// token when the local scope reset it to the guaranteed-invalid value.
|
|
81
|
+
else if (inherited?.getPropertyValue(name).trim()) values.set(name, 'initial')
|
|
82
|
+
}
|
|
83
|
+
for (const name of copied) {
|
|
84
|
+
if (!values.has(name)) portal.style.removeProperty(name)
|
|
85
|
+
}
|
|
86
|
+
copied.clear()
|
|
87
|
+
for (const [name, value] of values) {
|
|
88
|
+
if (portal.style.getPropertyValue(name) !== value) portal.style.setProperty(name, value)
|
|
89
|
+
copied.add(name)
|
|
90
|
+
}
|
|
91
|
+
portal.classList.toggle('dark', anchor.closest('.dark') !== null)
|
|
92
|
+
}
|
|
93
|
+
sync()
|
|
94
|
+
const stop = observeTheme(anchor, sync)
|
|
95
|
+
onCleanup(() => {
|
|
96
|
+
stop()
|
|
97
|
+
for (const name of copied) portal.style.removeProperty(name)
|
|
98
|
+
portal.classList.remove('dark')
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
}
|