@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.
Files changed (172) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/README.md +154 -2
  3. package/dist/components/ActionGroupRenderer.cjs +6 -6
  4. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  5. package/dist/components/ActionGroupRenderer.js +6 -6
  6. package/dist/components/ActionGroupRenderer.js.map +1 -1
  7. package/dist/components/AutocompleteDropdown.cjs +6 -6
  8. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  9. package/dist/components/AutocompleteDropdown.js +6 -6
  10. package/dist/components/AutocompleteDropdown.js.map +1 -1
  11. package/dist/components/AutocompleteFormField.cjs +6 -5
  12. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  13. package/dist/components/AutocompleteFormField.d.ts.map +1 -1
  14. package/dist/components/AutocompleteFormField.js +6 -5
  15. package/dist/components/AutocompleteFormField.js.map +1 -1
  16. package/dist/components/ChartJSRenderer.cjs +406 -70
  17. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  18. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  19. package/dist/components/ChartJSRenderer.js +407 -71
  20. package/dist/components/ChartJSRenderer.js.map +1 -1
  21. package/dist/components/ChatPrompt.cjs +5 -5
  22. package/dist/components/ChatPrompt.cjs.map +1 -1
  23. package/dist/components/ChatPrompt.js +5 -5
  24. package/dist/components/ChatPrompt.js.map +1 -1
  25. package/dist/components/ComponentToolbar.cjs +5 -5
  26. package/dist/components/ComponentToolbar.cjs.map +1 -1
  27. package/dist/components/ComponentToolbar.js +5 -5
  28. package/dist/components/ComponentToolbar.js.map +1 -1
  29. package/dist/components/DegradedFallback.cjs +35 -3
  30. package/dist/components/DegradedFallback.cjs.map +1 -1
  31. package/dist/components/DegradedFallback.d.ts +7 -0
  32. package/dist/components/DegradedFallback.d.ts.map +1 -1
  33. package/dist/components/DegradedFallback.js +35 -3
  34. package/dist/components/DegradedFallback.js.map +1 -1
  35. package/dist/components/ExpandableWrapper.cjs +10 -7
  36. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  37. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  38. package/dist/components/ExpandableWrapper.js +10 -7
  39. package/dist/components/ExpandableWrapper.js.map +1 -1
  40. package/dist/components/FormFieldRenderer.cjs +13 -12
  41. package/dist/components/FormFieldRenderer.cjs.map +1 -1
  42. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  43. package/dist/components/FormFieldRenderer.js +13 -12
  44. package/dist/components/FormFieldRenderer.js.map +1 -1
  45. package/dist/components/FormRenderer.cjs +1 -1
  46. package/dist/components/FormRenderer.cjs.map +1 -1
  47. package/dist/components/FormRenderer.js +1 -1
  48. package/dist/components/FormRenderer.js.map +1 -1
  49. package/dist/components/GenerativeUIErrorBoundary.cjs +1 -1
  50. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
  51. package/dist/components/GenerativeUIErrorBoundary.js +1 -1
  52. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
  53. package/dist/components/GhostText.cjs +2 -2
  54. package/dist/components/GhostText.cjs.map +1 -1
  55. package/dist/components/GhostText.js +2 -2
  56. package/dist/components/GhostText.js.map +1 -1
  57. package/dist/components/GraphRenderer.cjs +100 -29
  58. package/dist/components/GraphRenderer.cjs.map +1 -1
  59. package/dist/components/GraphRenderer.d.ts +1 -1
  60. package/dist/components/GraphRenderer.d.ts.map +1 -1
  61. package/dist/components/GraphRenderer.js +100 -29
  62. package/dist/components/GraphRenderer.js.map +1 -1
  63. package/dist/components/MissingValue.cjs +43 -0
  64. package/dist/components/MissingValue.cjs.map +1 -0
  65. package/dist/components/MissingValue.d.ts +27 -0
  66. package/dist/components/MissingValue.d.ts.map +1 -0
  67. package/dist/components/MissingValue.js +43 -0
  68. package/dist/components/MissingValue.js.map +1 -0
  69. package/dist/components/ModalRenderer.cjs +39 -31
  70. package/dist/components/ModalRenderer.cjs.map +1 -1
  71. package/dist/components/ModalRenderer.d.ts.map +1 -1
  72. package/dist/components/ModalRenderer.js +40 -32
  73. package/dist/components/ModalRenderer.js.map +1 -1
  74. package/dist/components/PortalDropdownMenu.cjs +6 -3
  75. package/dist/components/PortalDropdownMenu.cjs.map +1 -1
  76. package/dist/components/PortalDropdownMenu.d.ts.map +1 -1
  77. package/dist/components/PortalDropdownMenu.js +7 -4
  78. package/dist/components/PortalDropdownMenu.js.map +1 -1
  79. package/dist/components/ScratchpadPanel.cjs +38 -44
  80. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  81. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  82. package/dist/components/ScratchpadPanel.js +38 -44
  83. package/dist/components/ScratchpadPanel.js.map +1 -1
  84. package/dist/components/UIResourceRenderer.cjs +255 -217
  85. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  86. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  87. package/dist/components/UIResourceRenderer.js +255 -217
  88. package/dist/components/UIResourceRenderer.js.map +1 -1
  89. package/dist/components/chart-data-table.cjs +30 -5
  90. package/dist/components/chart-data-table.cjs.map +1 -1
  91. package/dist/components/chart-data-table.d.ts +18 -1
  92. package/dist/components/chart-data-table.d.ts.map +1 -1
  93. package/dist/components/chart-data-table.js +30 -5
  94. package/dist/components/chart-data-table.js.map +1 -1
  95. package/dist/components/chart-missing-plugin.cjs +194 -0
  96. package/dist/components/chart-missing-plugin.cjs.map +1 -0
  97. package/dist/components/chart-missing-plugin.d.ts +129 -0
  98. package/dist/components/chart-missing-plugin.d.ts.map +1 -0
  99. package/dist/components/chart-missing-plugin.js +194 -0
  100. package/dist/components/chart-missing-plugin.js.map +1 -0
  101. package/dist/context/MCPUIStringsContext.cjs +12 -1
  102. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  103. package/dist/context/MCPUIStringsContext.d.ts +62 -0
  104. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  105. package/dist/context/MCPUIStringsContext.js +12 -1
  106. package/dist/context/MCPUIStringsContext.js.map +1 -1
  107. package/dist/services/component-registry.cjs +9 -2
  108. package/dist/services/component-registry.cjs.map +1 -1
  109. package/dist/services/component-registry.d.ts.map +1 -1
  110. package/dist/services/component-registry.js +9 -2
  111. package/dist/services/component-registry.js.map +1 -1
  112. package/dist/services/validation.cjs +31 -8
  113. package/dist/services/validation.cjs.map +1 -1
  114. package/dist/services/validation.d.ts.map +1 -1
  115. package/dist/services/validation.js +31 -8
  116. package/dist/services/validation.js.map +1 -1
  117. package/dist/types/index.d.ts +14 -2
  118. package/dist/types/index.d.ts.map +1 -1
  119. package/dist/utils/degraded-projections.cjs +19 -3
  120. package/dist/utils/degraded-projections.cjs.map +1 -1
  121. package/dist/utils/degraded-projections.d.ts +22 -2
  122. package/dist/utils/degraded-projections.d.ts.map +1 -1
  123. package/dist/utils/degraded-projections.js +19 -3
  124. package/dist/utils/degraded-projections.js.map +1 -1
  125. package/dist/utils/math-markdown.cjs +1 -1
  126. package/dist/utils/math-markdown.cjs.map +1 -1
  127. package/dist/utils/math-markdown.js +1 -1
  128. package/dist/utils/math-markdown.js.map +1 -1
  129. package/dist/utils/missing-value.cjs +60 -0
  130. package/dist/utils/missing-value.cjs.map +1 -0
  131. package/dist/utils/missing-value.d.ts +79 -0
  132. package/dist/utils/missing-value.d.ts.map +1 -0
  133. package/dist/utils/missing-value.js +60 -0
  134. package/dist/utils/missing-value.js.map +1 -0
  135. package/dist/utils/theme.cjs +91 -0
  136. package/dist/utils/theme.cjs.map +1 -0
  137. package/dist/utils/theme.d.ts +11 -0
  138. package/dist/utils/theme.d.ts.map +1 -0
  139. package/dist/utils/theme.js +91 -0
  140. package/dist/utils/theme.js.map +1 -0
  141. package/docs/SECURITY-DEPENDENCIES.md +81 -0
  142. package/docs/THEMING.md +205 -0
  143. package/package.json +7 -5
  144. package/src/components/ActionGroupRenderer.tsx +6 -6
  145. package/src/components/AutocompleteDropdown.tsx +17 -17
  146. package/src/components/AutocompleteFormField.tsx +10 -9
  147. package/src/components/ChartJSRenderer.tsx +609 -212
  148. package/src/components/ChatPrompt.tsx +16 -16
  149. package/src/components/ComponentToolbar.tsx +5 -5
  150. package/src/components/DegradedFallback.tsx +33 -11
  151. package/src/components/ExpandableWrapper.tsx +15 -11
  152. package/src/components/FormFieldRenderer.tsx +52 -51
  153. package/src/components/FormRenderer.tsx +12 -12
  154. package/src/components/GenerativeUIErrorBoundary.tsx +6 -6
  155. package/src/components/GhostText.tsx +7 -7
  156. package/src/components/GraphRenderer.tsx +83 -67
  157. package/src/components/MissingValue.tsx +61 -0
  158. package/src/components/ModalRenderer.tsx +11 -5
  159. package/src/components/PortalDropdownMenu.tsx +6 -2
  160. package/src/components/ScratchpadPanel.tsx +144 -141
  161. package/src/components/UIResourceRenderer.tsx +143 -110
  162. package/src/components/chart-data-table.ts +50 -6
  163. package/src/components/chart-missing-plugin.ts +336 -0
  164. package/src/context/MCPUIStringsContext.tsx +76 -0
  165. package/src/services/component-registry.ts +10 -2
  166. package/src/services/validation.ts +44 -9
  167. package/src/styles/autocomplete.css +53 -53
  168. package/src/types/index.ts +13 -1
  169. package/src/utils/degraded-projections.ts +44 -4
  170. package/src/utils/math-markdown.ts +1 -1
  171. package/src/utils/missing-value.ts +127 -0
  172. package/src/utils/theme.ts +101 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,173 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [6.25.1] - 2026-10-18
9
+
10
+ ### Security
11
+
12
+ - Raise the published DOMPurify floor to `^3.4.17` (lockfile: 3.4.17), covering
13
+ both reported `IN_PLACE` advisories and subsequent upstream hardening. The
14
+ library's existing string-based sanitization profiles remain unchanged.
15
+ - Update workspace Solid to 1.9.17 and Seroval/Seroval plugins to 1.6.11,
16
+ using Solid's supported 1.6.x dependency range instead of the stale 1.5.x
17
+ override. Add real asynchronous SSR and JSON serialization compatibility tests.
18
+ - Update build/test resolutions to `source-map-js` 1.2.2 and `brace-expansion`
19
+ 5.0.12. Audit falls from nine advisories to one remaining HIGH advisory in
20
+ the distinct, unpatched development dependency `braces` 3.0.3. No audit ignore
21
+ or advisory dismissal is added; see `docs/SECURITY-DEPENDENCIES.md`.
22
+ - Workspace overrides do not propagate to consuming applications. Hosts must
23
+ separately update their Solid/Seroval lockfiles; the public Solid peer range
24
+ and component APIs are unchanged.
25
+
26
+ ## [6.25.0] - 2026-10-18
27
+
28
+ ### Added
29
+
30
+ - Inherited `--mcp-ui-*` CSS theme tokens with per-use original color fallbacks
31
+ for prompts, resource/table chrome, scratchpads, form controls, autocomplete,
32
+ expanded dialogs, export menus and chart/graph chrome. No required provider,
33
+ new dependency, global root defaults or component prop changes.
34
+ - Body portal theme synchronization, including local `.dark`, live ancestor
35
+ token changes and removal; fullscreen content retains its original DOM.
36
+ - Scoped Chart.js/G6 series, grid, axis, label and tooltip tokens with live
37
+ updates and explicit caller color precedence; original engine defaults are
38
+ retained when no host tokens are supplied.
39
+ - Frozen 6.24.0 Chromium computed-style comparisons, host/portal regressions,
40
+ static Tailwind class checks and theming documentation with coverage limits.
41
+
42
+ ### Fixed
43
+
44
+ - Form input and autocomplete text respects the host foreground without a
45
+ `.dark` class, preserving inherited default colors and muted field states.
46
+ - Explicit point paints no longer block themed line/radar strokes. Live
47
+ Chart.js theme updates also refresh resolved shared point/bar colors without
48
+ replacing their options or changing caller-provided non-color settings.
49
+
50
+ ## [6.24.0] - 2026-10-03
51
+
52
+ Explicit missing values in charts and tables, and a unit per chart — lot 1 of
53
+ the GeoAI display brief (`deposium_geoai/docs/handoffs/2026-10-03-mcp-ui-geoai-display-brief.md`).
54
+ Released with `@seed-ship/mcp-ui-spec` 5.7.0, whose chart schema accepts both;
55
+ the dependency floor moves to `^5.7.0`.
56
+
57
+ ### The rule
58
+
59
+ Absence is never zero. A `null` keeps its slot — its label stays on the axis,
60
+ its row stays in the table — and every view marks it, visibly and for screen
61
+ readers. Until now `validateComponent` refused any chart carrying a `null`, so
62
+ a host that drops invalid components (Deposium's chat does) showed nothing.
63
+
64
+ Only an explicit entry is a missing value: `null` (or a non-finite number, or a
65
+ point whose `y` is one). A dataset with no entry at all (`data: []`) is not —
66
+ it renders exactly as it did in 6.23.0.
67
+
68
+ ### Added
69
+
70
+ - **Charts accept `null`** in line, bar, radar, scatter and bubble datasets,
71
+ as a number slot or as a point's `y`:
72
+ - a line or a radar breaks at the missing value: `spanGaps: false` is set on
73
+ every dataset of a chart that has one, so nothing joins the neighbours,
74
+ and the date stays on the axis;
75
+ - a missing bar is drawn as a dashed outline at the baseline, so it cannot
76
+ be read as a zero bar (Chart.js draws nothing for both). Stacked or
77
+ overlaid bars get no outline — their baseline belongs to the series below,
78
+ so an outline there would point at the wrong series — and their note says
79
+ the values are not plotted;
80
+ - scatter and bubble charts leave the point out;
81
+ - a series whose every entry is missing keeps its legend entry, marked
82
+ `chartLegendNoData` ("(no data)"), and a chart with nothing to plot says
83
+ so in its plot area (`chartNoData`);
84
+ - a note under the chart explains how this chart shows a missing value
85
+ (`chartMissingGaps`, `chartMissingBars`, `chartMissingPoints`), shown when
86
+ a reader can actually see the mark, and names the series with no data
87
+ (`chartSeriesNoData`, joined with `Intl.ListFormat` in the strings
88
+ `locale`). The canvas's `aria-describedby` includes it. DOM hooks:
89
+ `[data-mcp-chart-notes]` and
90
+ `[data-mcp-chart-note="gaps|bars|omitted|no-data"]`;
91
+ - a tooltip names a missing bar (`missingValue`) instead of printing `0`.
92
+
93
+ Pie, doughnut and polar-area charts refuse `null`, as a bare value or as a
94
+ point's `y`, because Chart.js parses a missing share as `0` and would draw
95
+ every other share wrong. `validateChartComponent` reports
96
+ `MISSING_VALUE_UNSUPPORTED`. If a host bypasses validation, the renderer
97
+ shows its data table with `chartMissingUnsupported` instead of a misleading
98
+ chart.
99
+ - **`unit`** on chart params: the value-axis title (bar, line, scatter and
100
+ bubble, unless `options.scales` already sets one), the tooltip value
101
+ (`chartValueWithUnit`, except on scatter and bubble, whose value is a pair)
102
+ and the column headers of the data view and of the degraded table
103
+ (`chartLabelWithUnit`). `validateChartComponent` reports `INVALID_UNIT` for
104
+ a non-string unit or one longer than 32 characters; an empty string is
105
+ tolerated and means "no unit".
106
+ - **Tables.** A cell that already displayed as `-` — `null`, `undefined`, an
107
+ empty or whitespace-only string, `"undefined"` (after the backend's
108
+ `"X – undefined"` debris is stripped) or a literal `-` — is now muted,
109
+ hidden from assistive technology and followed by a visually-hidden
110
+ `missingValue`. A legend (`missingValueLegend`, `[data-mcp-missing-legend]`)
111
+ follows any table with such a cell. It is computed on every row, so it does
112
+ not flicker while paging. Missing cells sort last in both directions (an
113
+ empty string no longer sorts as `0`), a numeric column is detected from its
114
+ first present value, and search never matches a missing cell.
115
+ - **The chart data view and the degraded tables** mark missing cells the same
116
+ way, under the same legend. `chartToDataTable` and `chartToDegradedTable`
117
+ return an extra `missing` matrix shaped like `rows`, which still hold `''`.
118
+ One exception: the degraded table prints point data (scatter, bubble,
119
+ `{x, y}` series) as JSON, where `"y":null` reads as such, and does not mark
120
+ it. `DegradedFallback` takes an optional `missing` prop; the graph and map
121
+ degraded tables do not change.
122
+ - Ten `MCPUIStrings` keys (275 → 285), English defaults, French in the README
123
+ dictionary: `missingValue`, `missingValueLegend`, `chartMissingGaps`,
124
+ `chartMissingBars`, `chartMissingPoints`, `chartSeriesNoData`,
125
+ `chartLegendNoData`, `chartValueWithUnit`, `chartLabelWithUnit`,
126
+ `chartMissingUnsupported`.
127
+ - `examples/geoai-daily-forecast/`: a synthetic, clearly labelled GeoAI pilot
128
+ (daily table, one chart per variable, comparison, map, thresholds, sources
129
+ and limits) built with `createComparisonLayout`, `createGeographyLayout` and
130
+ `createEvidenceLayout`, with tests for the brief's validation criteria that a
131
+ library can check. Not published, since it is outside `files`;
132
+ type-checked by `pnpm typecheck` (`tsconfig.examples.json`).
133
+
134
+ ### Unchanged on purpose
135
+
136
+ - A chart with no missing entry and no unit builds exactly the 6.23.0
137
+ Chart.js config, and a table with no missing cell renders the 6.23.0 DOM
138
+ (both tested; the table against a capture taken before the change).
139
+ - `renderCellValue` still returns `-` for a missing value; it now shares its
140
+ `"X – undefined"` cleanup with the table marks, so both always agree. CSV
141
+ and TSV exports still write an empty field, JSON still writes `null`.
142
+ - Chart.js's default interaction (`nearest`, `intersect: true`) is kept. A
143
+ missing bar has no height, so its tooltip only appears in `index` mode.
144
+ - No time axis is introduced: daily dates are categorical ISO labels. The
145
+ opt-in QuickChart renderer receives the payload as before; the unit and the
146
+ missing-value outlines, notes and legend belong to the native renderer.
147
+
148
+ ### Changed — for code that reads these types
149
+
150
+ - `ChartComponentParams` datasets' `data` is now `Array<number | null>`, or
151
+ points whose `y` is `number | null`. Code that reads chart payloads under
152
+ `strictNullChecks` has to handle the missing value.
153
+ - `chartToDataTable` and `chartToDegradedTable` always return the extra
154
+ `missing` matrix; code asserting their exact shape sees one more key.
155
+ - `ChartDataTableLabels.withUnit` and `DegradedProjectionLabels.withUnit` are
156
+ new **optional** fields, so a complete labels table written for
157
+ 6.20.0–6.23.0 as an object literal still type-checks (a
158
+ `Record<keyof …, string>` does not, as with any new key).
159
+ `CHART_DATA_TABLE_LABELS` and `DEGRADED_PROJECTION_LABELS` are now typed
160
+ `Required<…>`.
161
+ - The `INVALID_DATA_TYPE` and `INVALID_POINT_DATA` messages now mention
162
+ `null`; the codes do not change.
163
+
164
+ ### For hosts
165
+
166
+ - **Deposium (consumer):** bump to 6.24.0 and add the ten keys to the French
167
+ dictionary; `satisfies Required<MCPUIStrings>` fails until they are there.
168
+ The visually-hidden text uses an inline style, not Tailwind's `sr-only`, so
169
+ the Tailwind configuration needs no change.
170
+ - **Producers:** emit `null` only in line, bar, radar, scatter and bubble
171
+ charts, never `0` for a missing value and never a shortened array. A
172
+ hand-copied schema mirror needs both `null` and `unit` (see the spec 5.7.0
173
+ changelog).
174
+
8
175
  ## [6.23.0] - 2026-09-18
9
176
 
10
177
  ### Added
package/README.md CHANGED
@@ -5,6 +5,63 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
5
5
  [![npm version](https://img.shields.io/npm/v/@seed-ship/mcp-ui-solid.svg)](https://www.npmjs.com/package/@seed-ship/mcp-ui-solid)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
+ ## What's New in v6.25.1
9
+
10
+ DOMPurify now requires `^3.4.17`. The workspace uses the compatible Solid
11
+ 1.9.17 patch with corrected Seroval and build-tool dependency resolutions,
12
+ covered by a real server-rendering/serialization smoke test. These workspace
13
+ overrides do not update an application's own Solid/Seroval lockfile.
14
+ See [security dependency notes](./docs/SECURITY-DEPENDENCIES.md) for host
15
+ upgrade guidance and the remaining unpatched development-tooling advisory.
16
+
17
+ ## What's New in v6.25.0
18
+
19
+ Inherited `--mcp-ui-*` CSS tokens theme prompts, resource/table chrome,
20
+ scratchpads, form controls, autocomplete and chart/graph chrome. Body portals
21
+ follow their local host theme; mounted Chart.js/G6 instances update without
22
+ losing their identity. Existing colors remain the defaults.
23
+
24
+ ## Theming
25
+
26
+ Set variables on an ancestor; no provider or extra stylesheet is required
27
+ for the Tailwind-based components. Keep scanning this package's `src/**/*.{ts,tsx}`
28
+ with Tailwind v4 and your existing class-based `.dark` variant.
29
+
30
+ ```css
31
+ .app-theme {
32
+ --mcp-ui-surface: #ffffff;
33
+ --mcp-ui-surface-muted: #f1f5f9;
34
+ --mcp-ui-fg: #0f172a;
35
+ --mcp-ui-fg-muted: #475569;
36
+ --mcp-ui-border: #cbd5e1;
37
+ --mcp-ui-accent: #1d4ed8;
38
+ }
39
+ .dark .app-theme {
40
+ --mcp-ui-surface: #0f172a;
41
+ --mcp-ui-surface-muted: #1e293b;
42
+ --mcp-ui-fg: #f8fafc;
43
+ --mcp-ui-fg-muted: #cbd5e1;
44
+ --mcp-ui-border: #64748b;
45
+ --mcp-ui-accent: #93c5fd;
46
+ }
47
+ ```
48
+
49
+ The library deliberately does not redeclare public tokens on nested roots:
50
+ an ancestor's tokens keep inheriting. Each use falls back to its original
51
+ color, preserving the existing light/dark distinctions. Optional autocomplete
52
+ CSS is still imported as before. See [the complete token reference, portal
53
+ behavior, contrast limits and migration coverage](./docs/THEMING.md).
54
+
55
+ ## What's New in v6.24.0
56
+
57
+ Explicit missing values in charts and tables, and a `unit` per chart. A `null`
58
+ in a line, bar, radar, scatter or bubble dataset is now accepted and shown as
59
+ missing, never as zero. Lines break, a missing bar gets a dashed outline, and a
60
+ note under the chart says how. Table cells with no value are announced to
61
+ screen readers and explained by a legend. Ten new `MCPUIStrings` keys; requires
62
+ `@seed-ship/mcp-ui-spec` 5.7.0. See
63
+ [Missing values and units in charts](#missing-values-and-units-in-charts-v6240).
64
+
8
65
  ## What's New in v6.23.0
9
66
 
10
67
  Opt-in LaTeX in markdown text components and table cells, with the same
@@ -715,6 +772,73 @@ Requires `protomaps-leaflet` peer dependency.
715
772
  }} />
716
773
  ```
717
774
 
775
+ ## Missing values and units in charts (v6.24.0)
776
+
777
+ `null` in a chart dataset is an **explicit missing value**: the value belongs
778
+ to the series' grid (its label stays on the axis) but was not observed. Send
779
+ `null` rather than `0`, and rather than a shorter array, whenever a value is
780
+ absent; a series with no value at all is all `null`.
781
+
782
+ ```tsx
783
+ <UIResourceRenderer content={{
784
+ id: 'wind',
785
+ type: 'chart',
786
+ position: { colStart: 1, colSpan: 12 },
787
+ params: {
788
+ type: 'line',
789
+ title: 'Wind speed',
790
+ unit: 'km/h',
791
+ data: {
792
+ labels: ['2026-10-04', '2026-10-05', '2026-10-06'],
793
+ datasets: [
794
+ { label: 'Lyon', data: [18, null, 31] }, // a hole on day 2
795
+ { label: 'Brest', data: [null, null, null] }, // no value at all
796
+ ],
797
+ },
798
+ },
799
+ }} />
800
+ ```
801
+
802
+ | Chart type | A missing value is drawn as | Note under the chart |
803
+ |---|---|---|
804
+ | `line`, `radar` | a break in the line — never joined to its neighbours (`spanGaps: false` is forced) | `chartMissingGaps` |
805
+ | `bar` | a dashed outline at the baseline, so it cannot read as a zero bar | `chartMissingBars` |
806
+ | `scatter`, `bubble` | nothing: the point is not plotted | `chartMissingPoints` |
807
+ | `bar` with `stacked` scales | nothing: the baseline belongs to the series below, so no outline is drawn | `chartMissingPoints` |
808
+ | `pie`, `doughnut`, `polarArea` | refused: Chart.js would draw a missing share as `0` — validation reports `MISSING_VALUE_UNSUPPORTED` | — |
809
+
810
+ A series whose every entry is `null` keeps its legend entry, marked
811
+ `chartLegendNoData`, and is named in a `chartSeriesNoData` note. A chart with
812
+ nothing to plot says `chartNoData` in its plot area. Only an explicit entry is
813
+ a missing value: a dataset with no entry (`data: []`) renders as it always
814
+ did. The notes are linked to
815
+ the canvas through `aria-describedby`, and the **Data** view marks every
816
+ missing cell with the same `-` and screen-reader text as the table component,
817
+ under a `missingValueLegend` line.
818
+
819
+ `unit` (one per chart — split values with different units into separate
820
+ charts) titles the value axis unless `options.scales` already does, follows
821
+ each tooltip value (`chartValueWithUnit`), and joins the data-view column
822
+ headers (`chartLabelWithUnit`).
823
+
824
+ Daily series read best with ISO dates as plain category labels, as above:
825
+ `timeAxis` needs a Chart.js date adapter the host must register itself.
826
+
827
+ Tables follow the same rule: a cell that displays as `-` — `null`,
828
+ `undefined`, an empty or whitespace-only string, `"undefined"`, or a literal
829
+ `-` — shows a muted `-` with a visually-hidden `missingValue`, a
830
+ `missingValueLegend` line follows the table, missing cells sort last, and
831
+ search never matches them.
832
+
833
+ The outlines, notes, legend marks and `unit` belong to the native Chart.js
834
+ renderer. The opt-in QuickChart renderer receives the payload as is.
835
+
836
+ A synthetic, end-to-end example — daily table, one chart per variable,
837
+ comparison, map, thresholds, sources and limits, built with the three
838
+ presentation recipes — lives in
839
+ [`examples/geoai-daily-forecast/`](./examples/geoai-daily-forecast/) (not
840
+ published; its tests run with the package's).
841
+
718
842
  ## Chat Bus — Agent Interactions (`@experimental`)
719
843
 
720
844
  Bidirectional event/command system for agent-driven chat interactions. Your app keeps full control of its chat UI — the bus adds structured interactivity on top.
@@ -1530,6 +1654,20 @@ formatMCPUIString('Export CSV ({count} rows)', { count: 42 }) // 'Export CSV (42
1530
1654
  | `sizeBytes` | `{size} B` | `ArtifactRenderer` — file size below 1 KB (template) |
1531
1655
  | `sizeKilobytes` | `{size} KB` | `ArtifactRenderer` — file size in kilobytes (template) |
1532
1656
  | `sizeMegabytes` | `{size} MB` | `ArtifactRenderer` — file size in megabytes (template) |
1657
+ | `zoomIn` | `Zoom in` | `LightboxOverlay`, `ChartJSRenderer` — zoom-in button `title`/`aria-label` (v6.22.0) |
1658
+ | `zoomOut` | `Zoom out` | `LightboxOverlay`, `ChartJSRenderer` — zoom-out button `title`/`aria-label` (v6.22.0) |
1659
+ | `zoomReset` | `Reset zoom` | `LightboxOverlay`, `ChartJSRenderer` — reset button, shown while zoomed (v6.22.0) |
1660
+ | `zoomLevel` | `Zoom {percent}%` | `LightboxOverlay` — zoom-level readout (template, v6.22.0) |
1661
+ | `missingValue` | `Missing value` | Tables, chart data view, degraded tables — screen-reader text of a missing cell; tooltip value of a missing bar (v6.24.0) |
1662
+ | `missingValueLegend` | `“{marker}” marks a missing value.` | Legend under a table or data view with a missing cell (template, `{marker}` = `-`, v6.24.0) |
1663
+ | `chartMissingGaps` | `Breaks in a line mark missing values.` | `ChartJSRenderer` — note under a line or radar chart with a missing value (v6.24.0) |
1664
+ | `chartMissingBars` | `Dashed outlines mark missing values.` | `ChartJSRenderer` — note under a bar chart with a missing value (v6.24.0) |
1665
+ | `chartMissingPoints` | `Missing values are not plotted.` | `ChartJSRenderer` — note under a scatter, bubble or stacked bar chart with a missing value (v6.24.0) |
1666
+ | `chartSeriesNoData` | `No data for {series}.` | `ChartJSRenderer` — note naming the series with no value at all (template, `{series}` joined as a list in `locale`, v6.24.0) |
1667
+ | `chartLegendNoData` | `{series} (no data)` | `ChartJSRenderer` — legend entry of a series with no value at all (template, v6.24.0) |
1668
+ | `chartValueWithUnit` | `{value} {unit}` | `ChartJSRenderer` — tooltip value followed by the chart `unit` (template, v6.24.0) |
1669
+ | `chartLabelWithUnit` | `{label} ({unit})` | Chart data view and degraded chart tables — column header followed by the chart `unit` (template, v6.24.0) |
1670
+ | `chartMissingUnsupported` | `This chart type cannot show missing values.` | `ChartJSRenderer` — shown instead of a pie, doughnut or polar-area chart that received a missing value (v6.24.0) |
1533
1671
 
1534
1672
  ### `locale` — number, date and sort formatting (default change in v6.20.0)
1535
1673
 
@@ -1867,6 +2005,20 @@ const fr: MCPUIStrings = {
1867
2005
  sizeBytes: '{size} o',
1868
2006
  sizeKilobytes: '{size} Ko',
1869
2007
  sizeMegabytes: '{size} Mo',
2008
+ zoomIn: 'Zoom avant',
2009
+ zoomOut: 'Zoom arrière',
2010
+ zoomReset: 'Réinitialiser le zoom',
2011
+ zoomLevel: 'Zoom {percent} %',
2012
+ missingValue: 'Valeur manquante',
2013
+ missingValueLegend: '« {marker} » signale une valeur manquante.',
2014
+ chartMissingGaps: 'Une interruption de la courbe signale une valeur manquante.',
2015
+ chartMissingBars: 'Un contour en pointillés signale une valeur manquante.',
2016
+ chartMissingPoints: 'Les valeurs manquantes ne sont pas tracées.',
2017
+ chartSeriesNoData: 'Aucune donnée pour {series}.',
2018
+ chartLegendNoData: '{series} (aucune donnée)',
2019
+ chartValueWithUnit: '{value} {unit}',
2020
+ chartLabelWithUnit: '{label} ({unit})',
2021
+ chartMissingUnsupported: 'Ce type de graphique ne peut pas afficher de valeurs manquantes.',
1870
2022
  }
1871
2023
 
1872
2024
  <MCPUIStringsProvider strings={fr}><App /></MCPUIStringsProvider>
@@ -1901,8 +2053,8 @@ exported default table:
1901
2053
  | `adapters/connector.ts` (`/adapters`) | `connectorResultToUILayout` | `options.messages?: Partial<ConnectorAdapterMessages>` | `DEFAULT_CONNECTOR_MESSAGES` | `degradedNotice`, `degradedVersionSuffix`, `versionWarning` |
1902
2054
  | `adapters/macro-run.ts` (`/adapters`) | `macroRunToScratchpadState`, `macroInterrogationToChatPromptConfig` | `options.messages?: Partial<MacroRunAdapterMessages>` | `DEFAULT_MACRO_RUN_MESSAGES` | `agentSectionTitle`, `progressSectionTitle`, `resultSectionTitle`, `runAborted`, `runFailed`, `confirmDefault` |
1903
2055
  | `services/validation.ts` (root, `/validation`) | `validateFieldValue`, `validateFormData` | `messages?: Partial<FormValidationMessages>` | `DEFAULT_VALIDATION_MESSAGES` | `required`, `mustBeChecked`, `minLength`, `maxLength`, `invalidPattern`, `invalidEmail`, `invalidNumber`, `minValue`, `maxValue`, `minDate`, `maxDate`, `invalidOption`, `invalidFormat` |
1904
- | `utils/degraded-projections.ts` (root) | `graphToDegradedTable`, `mapToDegradedTable`, `chartToDegradedTable` | `labels?: Partial<DegradedProjectionLabels>` | `DEGRADED_PROJECTION_LABELS` | `source`, `target`, `label`, `node`, `type`, `lat`, `lng`, `info`, `marker`, `feature`, `series` |
1905
- | `components/chart-data-table.ts` (root) | `chartToDataTable` | `labels?: Partial<ChartDataTableLabels>` | `CHART_DATA_TABLE_LABELS` | `series`, `point`, `label`, `seriesName`, `x`, `y`, `r` |
2056
+ | `utils/degraded-projections.ts` (root) | `graphToDegradedTable`, `mapToDegradedTable`, `chartToDegradedTable` | `labels?: Partial<DegradedProjectionLabels>` | `DEGRADED_PROJECTION_LABELS` | `source`, `target`, `label`, `node`, `type`, `lat`, `lng`, `info`, `marker`, `feature`, `series`, `withUnit` (optional, v6.24.0: `{label} ({unit})`, chart headers when the chart has a unit) |
2057
+ | `components/chart-data-table.ts` (root) | `chartToDataTable` | `labels?: Partial<ChartDataTableLabels>` | `CHART_DATA_TABLE_LABELS` | `series`, `point`, `label`, `seriesName`, `x`, `y`, `r`, `withUnit` (optional, v6.24.0: `{label} ({unit})`, value headers when the chart has a unit) |
1906
2058
  | `hooks/useStreamingUI.ts` (root, `/hooks`) | `useStreamingUI` | `options.messages?: Partial<StreamingUIMessages>` | `DEFAULT_STREAMING_UI_MESSAGES` | `initializing`, `connecting`, `loadingComponent`, `dashboardLoaded`, `errorProgress`, `connectionFailed`, `requestFailed`, `emptyResponse`, `serverSide`, `unknownError` |
1907
2059
 
1908
2060
  Every option is a trailing OPTIONAL parameter, so existing calls keep
@@ -33,17 +33,17 @@ const ActionButton = (props) => {
33
33
  const variantClass = () => {
34
34
  switch (props.action.variant) {
35
35
  case "primary":
36
- return "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500";
36
+ return "bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]";
37
37
  case "secondary":
38
- return "bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500";
38
+ return "bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-200,#e5e7eb))] text-[color:var(--mcp-ui-fg,var(--color-gray-800,#1f2937))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-300,#d1d5db))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-600,#4b5563))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
39
39
  case "outline":
40
- return "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500";
40
+ return "border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
41
41
  case "ghost":
42
- return "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500";
42
+ return "text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
43
43
  case "danger":
44
- return "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500";
44
+ return "bg-[color:var(--mcp-ui-danger,var(--color-red-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-red-500))]";
45
45
  default:
46
- return "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500";
46
+ return "bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]";
47
47
  }
48
48
  };
49
49
  const sizeClass = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"ActionGroupRenderer.cjs","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\nimport { safeUrl } from '../utils/safe-url'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={safeUrl(props.action.url ?? '') ?? '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || strings.actionGroupLabel}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","safeUrl","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","strings","useMCPUIStrings","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","actionGroupLabel","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ActionGroupRenderer.cjs","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\nimport { safeUrl } from '../utils/safe-url'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]'\n case 'secondary':\n return 'bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-200,#e5e7eb))] text-[color:var(--mcp-ui-fg,var(--color-gray-800,#1f2937))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-300,#d1d5db))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-600,#4b5563))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'outline':\n return 'border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'ghost':\n return 'text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'danger':\n return 'bg-[color:var(--mcp-ui-danger,var(--color-red-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-red-500))]'\n default:\n return 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={safeUrl(props.action.url ?? '') ?? '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || strings.actionGroupLabel}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","safeUrl","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","strings","useMCPUIStrings","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","actionGroupLabel","_$delegateEvents"],"mappings":"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"}
@@ -31,17 +31,17 @@ const ActionButton = (props) => {
31
31
  const variantClass = () => {
32
32
  switch (props.action.variant) {
33
33
  case "primary":
34
- return "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500";
34
+ return "bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]";
35
35
  case "secondary":
36
- return "bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500";
36
+ return "bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-200,#e5e7eb))] text-[color:var(--mcp-ui-fg,var(--color-gray-800,#1f2937))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-300,#d1d5db))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-600,#4b5563))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
37
37
  case "outline":
38
- return "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500";
38
+ return "border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
39
39
  case "ghost":
40
- return "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500";
40
+ return "text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]";
41
41
  case "danger":
42
- return "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500";
42
+ return "bg-[color:var(--mcp-ui-danger,var(--color-red-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-red-500))]";
43
43
  default:
44
- return "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500";
44
+ return "bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]";
45
45
  }
46
46
  };
47
47
  const sizeClass = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"ActionGroupRenderer.js","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\nimport { safeUrl } from '../utils/safe-url'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={safeUrl(props.action.url ?? '') ?? '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || strings.actionGroupLabel}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","safeUrl","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","strings","useMCPUIStrings","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","actionGroupLabel","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ActionGroupRenderer.js","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\nimport { safeUrl } from '../utils/safe-url'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]'\n case 'secondary':\n return 'bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-200,#e5e7eb))] text-[color:var(--mcp-ui-fg,var(--color-gray-800,#1f2937))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-300,#d1d5db))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-600,#4b5563))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'outline':\n return 'border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'ghost':\n return 'text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] focus:ring-[color:var(--mcp-ui-focus,var(--color-gray-500,#6b7280))]'\n case 'danger':\n return 'bg-[color:var(--mcp-ui-danger,var(--color-red-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-red-500))]'\n default:\n return 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={safeUrl(props.action.url ?? '') ?? '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || strings.actionGroupLabel}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","safeUrl","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","strings","useMCPUIStrings","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","actionGroupLabel","_$delegateEvents"],"mappings":";;;;;;AA0BA,MAAMA,eAGAC,CAAAA,UAAU;AACd,QAAM;AAAA,IAAEC;AAAAA,IAASC;AAAAA,IAAeC;AAAAA,EAAAA,IAAgBC,UAAAA;AAIhD,QAAMC,eAAeA,MACnBL,MAAMM,OAAOA,WAAW,eAAeN,MAAMM,OAAOA,WAAW;AAEjE,QAAMC,cAAc,OAAOC,MAAkB;AAC3C,QAAIR,MAAMM,OAAOG,SAAU;AAE3B,QAAIT,MAAMM,OAAOA,WAAW,eAAeN,MAAMM,OAAOI,UAAU;AAChEF,QAAEG,eAAAA;AACF,YAAMV,QAAQD,MAAMM,OAAOI,UAAUV,MAAMM,OAAOM,UAAU,EAAE;AAAA,IAChE,WAAWZ,MAAMM,OAAOA,WAAW,UAAU;AAI3CE,QAAEG,eAAAA;AACF,YAAMT,cAAc;AAAA,QAClBI,QAAQ;AAAA,QACRI,UAAUV,MAAMM,OAAOI,YAAY;AAAA,QACnCE,QAAQZ,MAAMM,OAAOM,UAAU,CAAA;AAAA,MAAC,CACjC;AAAA,IACH,WAAWZ,MAAMM,OAAOA,WAAW,UAAUN,MAAMM,OAAOO,KAAK;AAC7DC,aAAOC,KAAKf,MAAMM,OAAOO,KAAK,UAAU,qBAAqB;AAAA,IAC/D;AAAA,EACF;AAEA,QAAMG,aAAaA,MACjBhB,MAAMM,OAAOG,YAAaJ,aAAAA,KAAkBF,YAAAA;AAE9C,QAAMc,eAAeA,MAAM;AACzB,YAAQjB,MAAMM,OAAOY,SAAAA;AAAAA,MACnB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAEA,QAAMC,YAAYA,MAAM;AACtB,YAAQnB,MAAMM,OAAOc,MAAAA;AAAAA,MACnB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAGA,MAAIpB,MAAMM,OAAOe,SAAS,UAAWrB,MAAMM,OAAOA,WAAW,UAAUN,MAAMM,OAAOO,KAAM;AACxF,YAAA,MAAA;AAAA,UAAAS,OAAAC,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAA,CAAAC,OAAAC,IAAA,IAAAC,cAAAJ,MAAAK,WAAA,GAAAC,QAAAJ,MAAAG,aAAA,CAAAE,OAAAC,KAAA,IAAAJ,cAAAE,MAAAD,WAAA;AAAAI,aAAAZ,MAAAa,gBASKC,MAAI;AAAA,QAAA,IAACC,OAAI;AAAA,iBAAErC,MAAMM,OAAOgC;AAAAA,QAAI;AAAA,QAAA,IAAAC,WAAA;AAAA,cAAAC,QAAAjB,eAAAkB,MAAA;AAAAP,iBAAAM,OAAA,MACCxC,MAAMM,OAAOgC,IAAI;AAAA,iBAAAE;AAAAA,QAAA;AAAA,MAAA,CAAA,GAAAb,OAAAC,IAAA;AAAAM,aAAAZ,MAAA,MAE9CtB,MAAMM,OAAOoC,OAAKV,OAAAC,KAAA;AAAAU,aAAAC,CAAAA,QAAA;AAAA,YAAAC,MAVbC,QAAQ9C,MAAMM,OAAOO,OAAO,EAAE,KAAK,KAAGkC,OAGrC,8IAA8I9B,aAAAA,CAAc,IAAIE,UAAAA,CAAW,IAChLH,WAAAA,IAAe,sDAAsD,EAAE;AACvE6B,gBAAAD,IAAApC,KAAAwC,aAAA1B,MAAA,QAAAsB,IAAApC,IAAAqC,GAAA;AAAAE,iBAAAH,IAAAK,KAAAC,UAAA5B,MAAAsB,IAAAK,IAAAF,IAAA;AAAA,eAAAH;AAAAA,MAAA,GAAA;AAAA,QAAApC,GAAA2C;AAAAA,QAAAF,GAAAE;AAAAA,MAAAA,CAAA;AAAA,aAAA7B;AAAAA,IAAA,GAAA;AAAA,EAQR;AAEA,UAAA,MAAA;AAAA,QAAA8B,QAAA7B,eAAA8B,OAAA,GAAAC,QAAAF,MAAA1B,YAAA,CAAA6B,OAAAC,KAAA,IAAA3B,cAAAyB,MAAAxB,WAAA,GAAA2B,SAAAF,MAAAzB,aAAA,CAAA4B,QAAAC,KAAA,IAAA9B,cAAA4B,OAAA3B,WAAA,GAAA8B,SAAAF,OAAA5B,aAAA,CAAA+B,QAAAC,KAAA,IAAAjC,cAAA+B,OAAA9B,WAAA;AAAAsB,UAAAW,UAGaxD;AAAW2B,WAAAkB,OAAAjB,gBAMnBC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE2B,aAAA7D,aAAa,EAAA,KAAIE,aAAAA;AAAAA,MAAc;AAAA,MAAA,IAAAkC,WAAA;AAAA,eAAAhB,eAAA0C,OAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAAV,OAAAC,KAAA;AAAAtB,WAAAkB,OAAAjB,gBAG1CC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE2B,KAAA,MAAA,CAAA,CAAAhE,MAAMM,OAAOgC,IAAI,EAAA,KAAI,EAAEnC,iBAAiBE;MAAe;AAAA,MAAA,IAAAkC,WAAA;AAAA,YAAA2B,QAAA3C,eAAAkB,MAAA;AAAAP,eAAAgC,OAAA,MACrClE,MAAMM,OAAOgC,IAAI;AAAA,eAAA4B;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAR,QAAAC,KAAA;AAAAzB,WAAAkB,OAAA,MAE9CpD,MAAMM,OAAOoC,OAAKmB,QAAAC,KAAA;AAAAnB,WAAAC,CAAAA,QAAA;AAAA,UAAAuB,OAXTnD,WAAAA,GAAYoD,OACf,8IAA8InD,aAAAA,CAAc,IAAIE,UAAAA,CAAW,IAChLH,WAAAA,IAAe,kCAAkC,EAAE;AACnDmD,eAAAvB,IAAApC,KAAA6D,YAAAjB,OAAA,YAAAR,IAAApC,IAAA2D,IAAA;AAAAC,eAAAxB,IAAAK,KAAAC,UAAAE,OAAAR,IAAAK,IAAAmB,IAAA;AAAA,aAAAxB;AAAAA,IAAA,GAAA;AAAA,MAAApC,GAAA2C;AAAAA,MAAAF,GAAAE;AAAAA,IAAAA,CAAA;AAAAmB,uBAAAA;AAAA,WAAAlB;AAAAA,EAAA,GAAA;AAWR;AAuBO,MAAMmB,sBAA4DvE,CAAAA,UAAU;AACjF,QAAMwE,UAAUC,gBAAAA;AAChB,QAAM7D,SAASA,MAAAA;;AAAMZ,iBAAMY,YAAWZ,WAAM0E,cAAN1E,mBAAiBY,WAAgC;AAAA,MAAE+D,SAAS,CAAA;AAAA,IAAA;AAAA;AAElG,QAAMC,cAAcA,MAAM;;AACxB,aAAQhE,YAAAA,MAAAA,mBAAUiE,QAAAA;AAAAA,MAChB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAEA,QAAMC,WAAWA,MAAM;;AACrB,aAAQlE,YAAAA,MAAAA,mBAAUmE,KAAAA;AAAAA,MAChB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAEA,UAAA,MAAA;AAAA,QAAAC,SAAAzD,eAAA0D,OAAA;AAAA/C,WAAA8C,QAAA7C,gBAMK+C,KAAG;AAAA,MAAA,IAACC,OAAI;;AAAA,iBAAEvE,YAAAA,MAAAA,mBAAU+D,YAAW,CAAA;AAAA,MAAE;AAAA,MAAApC,UAC/BA,CAACjC,QAAQ8E,UAAKjD,gBAAMpC,cAAY;AAAA,QAACO;AAAAA,QAAc,IAAE8E,QAAK;AAAA,iBAAEA,MAAAA;AAAAA,QAAO;AAAA,MAAA,CAAA;AAAA,IAAA,CAAI,CAAA;AAAAzC,WAAAC,CAAAA,QAAA;;AAAA,UAAAyC,OAL/D,GAAGT,YAAAA,CAAa,IAAIE,SAAAA,CAAU,MAAIlE,YAAAA,MAAAA,mBAAU0E,aAAY,WAAW,EAAE,IAAEC,SAElE3E,kBAAAA,mBAAU8B,UAAS8B,QAAQgB;AAAgBH,eAAAzC,IAAApC,KAAA0C,UAAA8B,QAAApC,IAAApC,IAAA6E,IAAA;AAAAE,eAAA3C,IAAAK,KAAAD,aAAAgC,QAAA,cAAApC,IAAAK,IAAAsC,IAAA;AAAA,aAAA3C;AAAAA,IAAA,GAAA;AAAA,MAAApC,GAAA2C;AAAAA,MAAAF,GAAAE;AAAAA,IAAAA,CAAA;AAAA,WAAA6B;AAAAA,EAAA,GAAA;AAO7D;AAACS,eAAA,CAAA,OAAA,CAAA;"}
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
5
  const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
6
- var _tmpl$ = /* @__PURE__ */ web.template(`<strong class=mcp-autocomplete-highlight>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-icon>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-description>`), _tmpl$4 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-option-content><!$><!/><div class=mcp-autocomplete-option-text><span class=mcp-autocomplete-option-label></span><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-loading style="padding:12px 16px;color:#6b7280;font-size:0.875rem;display:flex;align-items:center;gap:8px"><span style="display:inline-block;width:14px;height:14px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:mcp-spin 0.6s linear infinite"></span><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-empty style="padding:12px 16px;color:#9ca3af;font-size:0.875rem;text-align:center">`), _tmpl$7 = /* @__PURE__ */ web.template(`<ul class=mcp-autocomplete-options style="margin:0;padding:4px 0;list-style:none">`), _tmpl$8 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-footer style="padding:6px 12px;border-top:1px solid #e5e7eb;background-color:#f9fafb;font-size:0.75rem;color:#6b7280"><kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↑</kbd> <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↓</kbd><!$><!/><kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Enter</kbd><!$><!/><kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Esc</kbd><!$><!/>`), _tmpl$9 = /* @__PURE__ */ web.template(`<div role=listbox><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$0 = /* @__PURE__ */ web.template(`<li role=option style="padding:8px 16px;font-size:0.875rem;transition:background-color 150ms ease">`);
6
+ var _tmpl$ = /* @__PURE__ */ web.template(`<strong class=mcp-autocomplete-highlight>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-icon>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-description>`), _tmpl$4 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-option-content><!$><!/><div class=mcp-autocomplete-option-text><span class=mcp-autocomplete-option-label></span><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-loading style="padding:12px 16px;color:var(--mcp-ui-fg-muted, #6b7280);font-size:0.875rem;display:flex;align-items:center;gap:8px"><span style="display:inline-block;width:14px;height:14px;border:2px solid var(--mcp-ui-border, #e5e7eb);border-top-color:var(--mcp-ui-accent, #3b82f6);border-radius:50%;animation:mcp-spin 0.6s linear infinite"></span><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-empty style="padding:12px 16px;color:var(--mcp-ui-fg-subtle, #9ca3af);font-size:0.875rem;text-align:center">`), _tmpl$7 = /* @__PURE__ */ web.template(`<ul class=mcp-autocomplete-options style="margin:0;padding:4px 0;list-style:none">`), _tmpl$8 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-footer style="padding:6px 12px;border-top:1px solid var(--mcp-ui-border, #e5e7eb);background-color:var(--mcp-ui-surface-muted, #f9fafb);font-size:0.75rem;color:var(--mcp-ui-fg-muted, #6b7280)"><kbd style="background-color:var(--mcp-ui-surface-hover, #e5e7eb);padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↑</kbd> <kbd style="background-color:var(--mcp-ui-surface-hover, #e5e7eb);padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↓</kbd><!$><!/><kbd style="background-color:var(--mcp-ui-surface-hover, #e5e7eb);padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Enter</kbd><!$><!/><kbd style="background-color:var(--mcp-ui-surface-hover, #e5e7eb);padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Esc</kbd><!$><!/>`), _tmpl$9 = /* @__PURE__ */ web.template(`<div role=listbox><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$0 = /* @__PURE__ */ web.template(`<li role=option style="padding:8px 16px;font-size:0.875rem;transition:background-color 150ms ease">`);
7
7
  function highlightText(text, match) {
8
8
  if (!match || !text) {
9
9
  return text;
@@ -70,10 +70,10 @@ const AutocompleteDropdown = (props) => {
70
70
  left: "0",
71
71
  right: "0",
72
72
  "z-index": "50",
73
- "background-color": "#ffffff",
74
- border: "1px solid #e5e7eb",
73
+ "background-color": "var(--mcp-ui-surface, #ffffff)",
74
+ border: "1px solid var(--mcp-ui-border, #e5e7eb)",
75
75
  "border-radius": "6px",
76
- "box-shadow": "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
76
+ "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))",
77
77
  "max-height": props.maxHeight || "240px",
78
78
  overflow: "auto",
79
79
  ...positionStyles()
@@ -150,7 +150,7 @@ const AutocompleteDropdown = (props) => {
150
150
  }
151
151
  }));
152
152
  web.effect((_p$) => {
153
- var _v$4 = isSelected(), _v$5 = isDisabled(), _v$6 = `mcp-autocomplete-option ${isSelected() ? "mcp-autocomplete-option-selected" : ""} ${isDisabled() ? "mcp-autocomplete-option-disabled" : ""}`, _v$7 = isDisabled() ? "not-allowed" : "pointer", _v$8 = isSelected() ? "#eff6ff" : "transparent", _v$9 = isDisabled() ? "#9ca3af" : "#374151";
153
+ var _v$4 = isSelected(), _v$5 = isDisabled(), _v$6 = `mcp-autocomplete-option ${isSelected() ? "mcp-autocomplete-option-selected" : ""} ${isDisabled() ? "mcp-autocomplete-option-disabled" : ""}`, _v$7 = isDisabled() ? "not-allowed" : "pointer", _v$8 = isSelected() ? "var(--mcp-ui-accent-soft, #eff6ff)" : "transparent", _v$9 = isDisabled() ? "var(--mcp-ui-fg-subtle, #9ca3af)" : "var(--mcp-ui-fg, #374151)";
154
154
  _v$4 !== _p$.e && web.setAttribute(_el$36, "aria-selected", _p$.e = _v$4);
155
155
  _v$5 !== _p$.t && web.setAttribute(_el$36, "aria-disabled", _p$.t = _v$5);
156
156
  _v$6 !== _p$.a && web.className(_el$36, _p$.a = _v$6);
@@ -187,7 +187,7 @@ const AutocompleteDropdown = (props) => {
187
187
  }
188
188
  }), _el$35, _co$0);
189
189
  web.effect((_p$) => {
190
- var _v$ = `mcp-autocomplete-dropdown ${props.class || ""}`, _v$2 = containerStyles(), _v$3 = strings.autocompleteSuggestions;
190
+ var _v$ = `mcp-ui-root mcp-autocomplete-dropdown ${props.class || ""}`, _v$2 = containerStyles(), _v$3 = strings.autocompleteSuggestions;
191
191
  _v$ !== _p$.e && web.className(_el$1, _p$.e = _v$);
192
192
  _p$.t = web.style(_el$1, _v$2, _p$.t);
193
193
  _v$3 !== _p$.a && web.setAttribute(_el$1, "aria-label", _p$.a = _v$3);