@seed-ship/mcp-ui-solid 6.21.0 → 6.22.0

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 (63) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/components/ChartJSRenderer.cjs +244 -68
  3. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  4. package/dist/components/ChartJSRenderer.d.ts +9 -0
  5. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  6. package/dist/components/ChartJSRenderer.js +246 -70
  7. package/dist/components/ChartJSRenderer.js.map +1 -1
  8. package/dist/components/ExpandableWrapper.cjs +9 -1
  9. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  10. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  11. package/dist/components/ExpandableWrapper.js +9 -1
  12. package/dist/components/ExpandableWrapper.js.map +1 -1
  13. package/dist/components/LightboxOverlay.cjs +139 -16
  14. package/dist/components/LightboxOverlay.cjs.map +1 -1
  15. package/dist/components/LightboxOverlay.d.ts +6 -0
  16. package/dist/components/LightboxOverlay.d.ts.map +1 -1
  17. package/dist/components/LightboxOverlay.js +141 -18
  18. package/dist/components/LightboxOverlay.js.map +1 -1
  19. package/dist/context/MCPUIConfigContext.cjs +2 -1
  20. package/dist/context/MCPUIConfigContext.cjs.map +1 -1
  21. package/dist/context/MCPUIConfigContext.d.ts +60 -11
  22. package/dist/context/MCPUIConfigContext.d.ts.map +1 -1
  23. package/dist/context/MCPUIConfigContext.js +2 -1
  24. package/dist/context/MCPUIConfigContext.js.map +1 -1
  25. package/dist/context/MCPUIStringsContext.cjs +6 -1
  26. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  27. package/dist/context/MCPUIStringsContext.d.ts +22 -0
  28. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  29. package/dist/context/MCPUIStringsContext.js +6 -1
  30. package/dist/context/MCPUIStringsContext.js.map +1 -1
  31. package/dist/hooks/index.d.ts +2 -0
  32. package/dist/hooks/index.d.ts.map +1 -1
  33. package/dist/hooks.cjs +2 -0
  34. package/dist/hooks.cjs.map +1 -1
  35. package/dist/hooks.js +2 -0
  36. package/dist/hooks.js.map +1 -1
  37. package/dist/index.cjs +6 -0
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +2 -0
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +7 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/utils/iframe-coep.cjs.map +1 -1
  45. package/dist/utils/iframe-coep.d.ts +9 -2
  46. package/dist/utils/iframe-coep.d.ts.map +1 -1
  47. package/dist/utils/iframe-coep.js.map +1 -1
  48. package/dist/utils/pan-zoom.cjs +312 -0
  49. package/dist/utils/pan-zoom.cjs.map +1 -0
  50. package/dist/utils/pan-zoom.d.ts +235 -0
  51. package/dist/utils/pan-zoom.d.ts.map +1 -0
  52. package/dist/utils/pan-zoom.js +312 -0
  53. package/dist/utils/pan-zoom.js.map +1 -0
  54. package/package.json +5 -1
  55. package/src/components/ChartJSRenderer.tsx +396 -1
  56. package/src/components/ExpandableWrapper.tsx +26 -0
  57. package/src/components/LightboxOverlay.tsx +280 -4
  58. package/src/context/MCPUIConfigContext.tsx +62 -11
  59. package/src/context/MCPUIStringsContext.tsx +30 -0
  60. package/src/hooks/index.ts +13 -0
  61. package/src/index.ts +16 -0
  62. package/src/utils/iframe-coep.ts +9 -2
  63. package/src/utils/pan-zoom.ts +779 -0
@@ -1,12 +1,13 @@
1
- import { createComponent, getNextElement, getNextMarker, insert, effect, setProperty, setAttribute, runHydrationEvents, mergeProps, memo, className, style, template, use, delegateEvents } from "solid-js/web";
2
- import { createSignal, createMemo, createUniqueId, createEffect, onCleanup, Show, For } from "solid-js";
1
+ import { createComponent, getNextElement, getNextMarker, insert, effect, setAttribute, runHydrationEvents, setProperty, mergeProps, memo, className, style, template, use, delegateEvents } from "solid-js/web";
2
+ import { createSignal, createMemo, createUniqueId, createEffect, untrack, onCleanup, Show, For } from "solid-js";
3
3
  import { ExpandableWrapper, useExpanded } from "./ExpandableWrapper.js";
4
4
  import { DegradedFallback } from "./DegradedFallback.js";
5
5
  import { chartToDataTable } from "./chart-data-table.js";
6
6
  import { useTelemetry } from "../context/MCPUITelemetryContext.js";
7
+ import { useMCPUIConfig } from "../context/MCPUIConfigContext.js";
7
8
  import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
8
9
  import { formatMCPUIString } from "../utils/format-string.js";
9
- var _tmpl$ = /* @__PURE__ */ template(`<h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<button type=button class="opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">`), _tmpl$3 = /* @__PURE__ */ template(`<tr><td class="px-3 py-6 text-center text-gray-500 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ template(`<div><table class="w-full border-collapse text-left text-sm"><caption class=sr-only><!$><!/> — <!$><!/></caption><thead class="bg-gray-50 dark:bg-gray-900/40"><tr></tr></thead><tbody><!$><!/><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80"><div class="flex flex-col items-center gap-2"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div><span class="text-sm text-gray-500 dark:text-gray-400">`), _tmpl$6 = /* @__PURE__ */ template(`<div><div class="flex items-center justify-between gap-3 mb-3 flex-shrink-0"><div class=min-w-0></div><div class="flex items-center gap-2"><div class="inline-flex rounded-md border border-gray-200 p-0.5 dark:border-gray-600"role=group><button type=button></button><button type=button></button></div><!$><!/></div></div><p class=sr-only><!$><!/>. <!$><!/></p><!$><!/><!$><!/><div><canvas role=img></canvas><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<th scope=col class="px-3 py-2 font-medium text-gray-900 dark:text-gray-100">`), _tmpl$8 = /* @__PURE__ */ template(`<tr class="border-t border-gray-100 dark:border-gray-700">`), _tmpl$9 = /* @__PURE__ */ template(`<td class="px-3 py-2 text-gray-700 dark:text-gray-300">`);
10
+ var _tmpl$ = /* @__PURE__ */ template(`<h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<button type=button class="opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">`), _tmpl$3 = /* @__PURE__ */ template(`<div class="inline-flex items-center gap-1"><button type=button class="opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM13.5 10.5h-6"></path></svg></button><button type=button class="opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM10.5 7.5v6m3-3h-6"></path></svg></button><!$><!/>`), _tmpl$4 = /* @__PURE__ */ template(`<button type=button class="opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">`), _tmpl$5 = /* @__PURE__ */ template(`<tr><td class="px-3 py-6 text-center text-gray-500 dark:text-gray-400">`), _tmpl$6 = /* @__PURE__ */ template(`<div><table class="w-full border-collapse text-left text-sm"><caption class=sr-only><!$><!/> — <!$><!/></caption><thead class="bg-gray-50 dark:bg-gray-900/40"><tr></tr></thead><tbody><!$><!/><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80"><div class="flex flex-col items-center gap-2"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div><span class="text-sm text-gray-500 dark:text-gray-400">`), _tmpl$8 = /* @__PURE__ */ template(`<div><div class="flex items-center justify-between gap-3 mb-3 flex-shrink-0"><div class=min-w-0></div><div class="flex items-center gap-2"><div class="inline-flex rounded-md border border-gray-200 p-0.5 dark:border-gray-600"role=group><button type=button></button><button type=button></button></div><!$><!/><!$><!/></div></div><p class=sr-only><!$><!/>. <!$><!/></p><!$><!/><!$><!/><div><canvas role=img></canvas><!$><!/>`), _tmpl$9 = /* @__PURE__ */ template(`<th scope=col class="px-3 py-2 font-medium text-gray-900 dark:text-gray-100">`), _tmpl$0 = /* @__PURE__ */ template(`<tr class="border-t border-gray-100 dark:border-gray-700">`), _tmpl$1 = /* @__PURE__ */ template(`<td class="px-3 py-2 text-gray-700 dark:text-gray-300">`);
10
11
  let ChartJS = null;
11
12
  let chartJSLoadPromise = null;
12
13
  const loadChartJS = async () => {
@@ -30,16 +31,78 @@ async function isChartJSAvailable() {
30
31
  return false;
31
32
  }
32
33
  }
34
+ let zoomPluginPromise = null;
35
+ let zoomPluginRegistered = false;
36
+ const loadZoomPlugin = () => {
37
+ if (!zoomPluginPromise) {
38
+ zoomPluginPromise = import(
39
+ /* @vite-ignore */
40
+ "chartjs-plugin-zoom"
41
+ ).then((module) => module.default ?? module).catch(() => null);
42
+ }
43
+ return zoomPluginPromise;
44
+ };
45
+ const ensureZoomPlugin = async () => {
46
+ try {
47
+ const plugin = await loadZoomPlugin();
48
+ if (!plugin) return null;
49
+ if (!zoomPluginRegistered) {
50
+ const Chart = await loadChartJS();
51
+ if (typeof (Chart == null ? void 0 : Chart.register) !== "function") return null;
52
+ Chart.register(plugin);
53
+ zoomPluginRegistered = true;
54
+ }
55
+ return plugin;
56
+ } catch {
57
+ return null;
58
+ }
59
+ };
60
+ const ZOOMABLE_CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "scatter", "bubble"]);
61
+ const CHART_ZOOM_BUTTON_FACTOR = 1.5;
62
+ const isChartZoomed = (chart) => {
63
+ var _a;
64
+ if (typeof (chart == null ? void 0 : chart.isZoomedOrPanned) === "function") return Boolean(chart.isZoomedOrPanned());
65
+ const level = (_a = chart == null ? void 0 : chart.getZoomLevel) == null ? void 0 : _a.call(chart);
66
+ return typeof level === "number" ? level !== 1 : false;
67
+ };
68
+ const isPlainZoomObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
69
+ const mergeZoomOptions = (base, override) => {
70
+ if (!isPlainZoomObject(override)) return base;
71
+ const merged = {
72
+ ...base
73
+ };
74
+ for (const [key, value] of Object.entries(override)) {
75
+ if (value === void 0) continue;
76
+ const ours = merged[key];
77
+ if (isPlainZoomObject(ours) && isPlainZoomObject(value)) {
78
+ merged[key] = mergeZoomOptions(ours, value);
79
+ } else if (typeof ours === "function" && typeof value === "function") {
80
+ const rendererHook = ours;
81
+ const callerHook = value;
82
+ merged[key] = (...args) => {
83
+ rendererHook(...args);
84
+ return callerHook(...args);
85
+ };
86
+ } else {
87
+ merged[key] = value;
88
+ }
89
+ }
90
+ return merged;
91
+ };
33
92
  const ContextAwareChartLayout = (props) => props.render(useExpanded());
34
93
  const ChartJSRenderer = (props) => {
35
94
  const [isLoading, setIsLoading] = createSignal(true);
36
95
  const [error, setError] = createSignal();
37
96
  const [activeView, setActiveView] = createSignal("chart");
97
+ const [isExpanded, setIsExpanded] = createSignal(false);
98
+ const [zoomPlugin, setZoomPlugin] = createSignal(null);
99
+ const [isZoomed, setIsZoomed] = createSignal(false);
38
100
  let canvasRef;
39
101
  let chartInstance;
40
102
  let renderVersion = 0;
41
103
  const params = () => props.component.params;
42
104
  const telemetry = useTelemetry();
105
+ const config = useMCPUIConfig();
43
106
  const strings = useMCPUIStrings();
44
107
  const tableData = createMemo(() => chartToDataTable(params(), {
45
108
  series: strings.chartTableSeries,
@@ -54,6 +117,60 @@ const ChartJSRenderer = (props) => {
54
117
  type: params().type,
55
118
  data: params().data
56
119
  }, null, 2);
120
+ const zoomWanted = createMemo(() => {
121
+ var _a, _b;
122
+ if (!ZOOMABLE_CHART_TYPES.has(params().type)) return false;
123
+ const hostZoom = (_b = (_a = params().options) == null ? void 0 : _a.plugins) == null ? void 0 : _b.zoom;
124
+ if (hostZoom === false || hostZoom === null) return false;
125
+ const mode = config.chartZoom;
126
+ if (mode === "never") return false;
127
+ if (mode === "always") return true;
128
+ return isExpanded();
129
+ });
130
+ createEffect(() => {
131
+ if (!zoomWanted() || untrack(zoomPlugin)) return;
132
+ void ensureZoomPlugin().then((plugin) => {
133
+ if (plugin) setZoomPlugin(() => plugin);
134
+ });
135
+ });
136
+ const zoomPluginOptions = {
137
+ zoom: {
138
+ wheel: {
139
+ enabled: true
140
+ },
141
+ pinch: {
142
+ enabled: true
143
+ },
144
+ // Drag is reserved for panning below; a drag-to-select zoom would make
145
+ // the two gestures fight over the same mouse button.
146
+ drag: {
147
+ enabled: false
148
+ },
149
+ mode: "xy",
150
+ onZoom: ({
151
+ chart
152
+ }) => setIsZoomed(isChartZoomed(chart))
153
+ },
154
+ pan: {
155
+ enabled: true,
156
+ mode: "xy",
157
+ onPan: ({
158
+ chart
159
+ }) => setIsZoomed(isChartZoomed(chart))
160
+ }
161
+ };
162
+ const zoomOptions = createMemo(() => zoomWanted() && zoomPlugin() ? zoomPluginOptions : null);
163
+ const zoomControlsShown = () => Boolean(zoomOptions()) && activeView() === "chart" && !error();
164
+ const handleZoomBy = (factor) => {
165
+ var _a;
166
+ (_a = chartInstance == null ? void 0 : chartInstance.zoom) == null ? void 0 : _a.call(chartInstance, factor);
167
+ setIsZoomed(isChartZoomed(chartInstance));
168
+ };
169
+ const handleResetZoom = () => {
170
+ var _a;
171
+ (_a = chartInstance == null ? void 0 : chartInstance.resetZoom) == null ? void 0 : _a.call(chartInstance);
172
+ setIsZoomed(false);
173
+ };
57
174
  const handleExportPNG = () => {
58
175
  if (!canvasRef) return;
59
176
  const url = canvasRef.toDataURL("image/png");
@@ -63,9 +180,10 @@ const ChartJSRenderer = (props) => {
63
180
  a.click();
64
181
  };
65
182
  createEffect(async () => {
66
- var _a, _b, _c, _d, _e, _f;
183
+ var _a, _b, _c, _d, _e, _f, _g, _h;
67
184
  if (!canvasRef) return;
68
185
  const chartParams = params();
186
+ const zoom = zoomOptions();
69
187
  const version = ++renderVersion;
70
188
  setIsLoading(true);
71
189
  setError(void 0);
@@ -76,17 +194,28 @@ const ChartJSRenderer = (props) => {
76
194
  chartInstance.destroy();
77
195
  chartInstance = null;
78
196
  }
197
+ const hostZoomOptions = (_b = (_a = chartParams.options) == null ? void 0 : _a.plugins) == null ? void 0 : _b.zoom;
79
198
  const baseOptions = {
80
199
  responsive: true,
81
200
  maintainAspectRatio: false,
82
201
  ...chartParams.options,
83
202
  plugins: {
84
- ...(_a = chartParams.options) == null ? void 0 : _a.plugins,
203
+ ...(_c = chartParams.options) == null ? void 0 : _c.plugins,
85
204
  legend: {
86
205
  display: true,
87
206
  position: "bottom",
88
- ...(_c = (_b = chartParams.options) == null ? void 0 : _b.plugins) == null ? void 0 : _c.legend
89
- }
207
+ ...(_e = (_d = chartParams.options) == null ? void 0 : _d.plugins) == null ? void 0 : _e.legend
208
+ },
209
+ // Present only once the optional peer has loaded AND the current
210
+ // surface wants zoom. Merged rather than assigned, so a consumer's
211
+ // own `plugins.zoom` survives; when zoom is off, the spread above
212
+ // has already left their block exactly as they wrote it.
213
+ // An explicit `plugins.zoom: false` never reaches here: `zoomWanted`
214
+ // already returned false for it, so `zoom` is null and the spread
215
+ // above carries the host's own value through untouched.
216
+ ...zoom ? {
217
+ zoom: mergeZoomOptions(zoom, hostZoomOptions)
218
+ } : {}
90
219
  }
91
220
  };
92
221
  if (chartParams.timeAxis) {
@@ -94,7 +223,7 @@ const ChartJSRenderer = (props) => {
94
223
  baseOptions.scales = {
95
224
  ...baseOptions.scales,
96
225
  x: {
97
- ...(_d = baseOptions.scales) == null ? void 0 : _d.x,
226
+ ...(_f = baseOptions.scales) == null ? void 0 : _f.x,
98
227
  type: "time",
99
228
  time: {
100
229
  parser: ta.parser,
@@ -115,6 +244,7 @@ const ChartJSRenderer = (props) => {
115
244
  data: chartParams.data,
116
245
  options: baseOptions
117
246
  });
247
+ setIsZoomed(false);
118
248
  setIsLoading(false);
119
249
  } catch (err) {
120
250
  if (version !== renderVersion) return;
@@ -124,11 +254,11 @@ const ChartJSRenderer = (props) => {
124
254
  telemetry == null ? void 0 : telemetry.dispatch({
125
255
  type: "render:error",
126
256
  errorMessage: error2.message,
127
- id: ((_e = props.component) == null ? void 0 : _e.id) ?? "",
257
+ id: ((_g = props.component) == null ? void 0 : _g.id) ?? "",
128
258
  componentType: "chart",
129
259
  ts: Date.now()
130
260
  });
131
- (_f = props.onError) == null ? void 0 : _f.call(props, error2);
261
+ (_h = props.onError) == null ? void 0 : _h.call(props, error2);
132
262
  }
133
263
  });
134
264
  createEffect(() => {
@@ -158,10 +288,11 @@ const ChartJSRenderer = (props) => {
158
288
  get toolbarVariant() {
159
289
  return props.toolbarVariant;
160
290
  },
291
+ onExpandedChange: setIsExpanded,
161
292
  get children() {
162
293
  return createComponent(ContextAwareChartLayout, {
163
- render: (isExpanded) => (() => {
164
- var _el$ = getNextElement(_tmpl$6), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$3.nextSibling, _el$6 = _el$5.firstChild, _el$7 = _el$6.firstChild, _el$8 = _el$7.nextSibling, _el$0 = _el$6.nextSibling, [_el$1, _co$] = getNextMarker(_el$0.nextSibling), _el$10 = _el$2.nextSibling, _el$12 = _el$10.firstChild, [_el$13, _co$2] = getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling, _el$14 = _el$11.nextSibling, [_el$15, _co$3] = getNextMarker(_el$14.nextSibling), _el$41 = _el$10.nextSibling, [_el$42, _co$9] = getNextMarker(_el$41.nextSibling), _el$43 = _el$42.nextSibling, [_el$44, _co$0] = getNextMarker(_el$43.nextSibling), _el$33 = _el$44.nextSibling, _el$34 = _el$33.firstChild, _el$39 = _el$34.nextSibling, [_el$40, _co$8] = getNextMarker(_el$39.nextSibling);
294
+ render: (isExpanded2) => (() => {
295
+ var _el$ = getNextElement(_tmpl$8), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$3.nextSibling, _el$6 = _el$5.firstChild, _el$7 = _el$6.firstChild, _el$8 = _el$7.nextSibling, _el$14 = _el$6.nextSibling, [_el$15, _co$2] = getNextMarker(_el$14.nextSibling), _el$16 = _el$15.nextSibling, [_el$17, _co$3] = getNextMarker(_el$16.nextSibling), _el$18 = _el$2.nextSibling, _el$20 = _el$18.firstChild, [_el$21, _co$4] = getNextMarker(_el$20.nextSibling), _el$19 = _el$21.nextSibling, _el$22 = _el$19.nextSibling, [_el$23, _co$5] = getNextMarker(_el$22.nextSibling), _el$49 = _el$18.nextSibling, [_el$50, _co$1] = getNextMarker(_el$49.nextSibling), _el$51 = _el$50.nextSibling, [_el$52, _co$10] = getNextMarker(_el$51.nextSibling), _el$41 = _el$52.nextSibling, _el$42 = _el$41.firstChild, _el$47 = _el$42.nextSibling, [_el$48, _co$0] = getNextMarker(_el$47.nextSibling);
165
296
  insert(_el$3, createComponent(Show, {
166
297
  get when() {
167
298
  return params().title;
@@ -176,18 +307,63 @@ const ChartJSRenderer = (props) => {
176
307
  insert(_el$7, () => strings.chartView);
177
308
  _el$8.$$click = () => setActiveView("data");
178
309
  insert(_el$8, () => strings.chartDataView);
310
+ insert(_el$5, createComponent(Show, {
311
+ get when() {
312
+ return zoomControlsShown();
313
+ },
314
+ get children() {
315
+ var _el$9 = getNextElement(_tmpl$3), _el$0 = _el$9.firstChild, _el$1 = _el$0.nextSibling, _el$11 = _el$1.nextSibling, [_el$12, _co$] = getNextMarker(_el$11.nextSibling);
316
+ _el$0.$$click = () => handleZoomBy(1 / CHART_ZOOM_BUTTON_FACTOR);
317
+ _el$1.$$click = () => handleZoomBy(CHART_ZOOM_BUTTON_FACTOR);
318
+ insert(_el$9, createComponent(Show, {
319
+ get when() {
320
+ return isZoomed();
321
+ },
322
+ get children() {
323
+ var _el$10 = getNextElement(_tmpl$2);
324
+ _el$10.$$click = handleResetZoom;
325
+ effect((_p$) => {
326
+ var _v$ = strings.zoomReset, _v$2 = strings.zoomReset;
327
+ _v$ !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$);
328
+ _v$2 !== _p$.t && setAttribute(_el$10, "aria-label", _p$.t = _v$2);
329
+ return _p$;
330
+ }, {
331
+ e: void 0,
332
+ t: void 0
333
+ });
334
+ runHydrationEvents();
335
+ return _el$10;
336
+ }
337
+ }), _el$12, _co$);
338
+ effect((_p$) => {
339
+ var _v$3 = strings.zoomOut, _v$4 = strings.zoomOut, _v$5 = strings.zoomIn, _v$6 = strings.zoomIn;
340
+ _v$3 !== _p$.e && setAttribute(_el$0, "title", _p$.e = _v$3);
341
+ _v$4 !== _p$.t && setAttribute(_el$0, "aria-label", _p$.t = _v$4);
342
+ _v$5 !== _p$.a && setAttribute(_el$1, "title", _p$.a = _v$5);
343
+ _v$6 !== _p$.o && setAttribute(_el$1, "aria-label", _p$.o = _v$6);
344
+ return _p$;
345
+ }, {
346
+ e: void 0,
347
+ t: void 0,
348
+ a: void 0,
349
+ o: void 0
350
+ });
351
+ runHydrationEvents();
352
+ return _el$9;
353
+ }
354
+ }), _el$15, _co$2);
179
355
  insert(_el$5, createComponent(Show, {
180
356
  get when() {
181
357
  return exportEnabled();
182
358
  },
183
359
  get children() {
184
- var _el$9 = getNextElement(_tmpl$2);
185
- _el$9.$$click = handleExportPNG;
360
+ var _el$13 = getNextElement(_tmpl$4);
361
+ _el$13.$$click = handleExportPNG;
186
362
  effect((_p$) => {
187
- var _v$ = activeView() !== "chart" || isLoading() || Boolean(error()), _v$2 = strings.chartDownloadPng, _v$3 = strings.chartDownloadPngAria;
188
- _v$ !== _p$.e && setProperty(_el$9, "disabled", _p$.e = _v$);
189
- _v$2 !== _p$.t && setAttribute(_el$9, "title", _p$.t = _v$2);
190
- _v$3 !== _p$.a && setAttribute(_el$9, "aria-label", _p$.a = _v$3);
363
+ var _v$7 = activeView() !== "chart" || isLoading() || Boolean(error()), _v$8 = strings.chartDownloadPng, _v$9 = strings.chartDownloadPngAria;
364
+ _v$7 !== _p$.e && setProperty(_el$13, "disabled", _p$.e = _v$7);
365
+ _v$8 !== _p$.t && setAttribute(_el$13, "title", _p$.t = _v$8);
366
+ _v$9 !== _p$.a && setAttribute(_el$13, "aria-label", _p$.a = _v$9);
191
367
  return _p$;
192
368
  }, {
193
369
  e: void 0,
@@ -195,12 +371,12 @@ const ChartJSRenderer = (props) => {
195
371
  a: void 0
196
372
  });
197
373
  runHydrationEvents();
198
- return _el$9;
374
+ return _el$13;
199
375
  }
200
- }), _el$1, _co$);
201
- setAttribute(_el$10, "id", descriptionId);
202
- insert(_el$10, title, _el$13, _co$2);
203
- insert(_el$10, () => strings.chartDataSummary, _el$15, _co$3);
376
+ }), _el$17, _co$3);
377
+ setAttribute(_el$18, "id", descriptionId);
378
+ insert(_el$18, title, _el$21, _co$4);
379
+ insert(_el$18, () => strings.chartDataSummary, _el$23, _co$5);
204
380
  insert(_el$, createComponent(Show, {
205
381
  get when() {
206
382
  return memo(() => !!error())() && activeView() === "chart";
@@ -217,103 +393,103 @@ const ChartJSRenderer = (props) => {
217
393
  }
218
394
  }, tableData));
219
395
  }
220
- }), _el$42, _co$9);
396
+ }), _el$50, _co$1);
221
397
  insert(_el$, createComponent(Show, {
222
398
  get when() {
223
399
  return activeView() === "data";
224
400
  },
225
401
  get children() {
226
- var _el$16 = getNextElement(_tmpl$4), _el$17 = _el$16.firstChild, _el$18 = _el$17.firstChild, _el$20 = _el$18.firstChild, [_el$21, _co$4] = getNextMarker(_el$20.nextSibling), _el$19 = _el$21.nextSibling, _el$22 = _el$19.nextSibling, [_el$23, _co$5] = getNextMarker(_el$22.nextSibling), _el$24 = _el$18.nextSibling, _el$25 = _el$24.firstChild, _el$26 = _el$24.nextSibling, _el$29 = _el$26.firstChild, [_el$30, _co$6] = getNextMarker(_el$29.nextSibling), _el$31 = _el$30.nextSibling, [_el$32, _co$7] = getNextMarker(_el$31.nextSibling);
227
- insert(_el$18, title, _el$21, _co$4);
228
- insert(_el$18, () => strings.chartDataTable, _el$23, _co$5);
229
- insert(_el$25, createComponent(For, {
402
+ var _el$24 = getNextElement(_tmpl$6), _el$25 = _el$24.firstChild, _el$26 = _el$25.firstChild, _el$28 = _el$26.firstChild, [_el$29, _co$6] = getNextMarker(_el$28.nextSibling), _el$27 = _el$29.nextSibling, _el$30 = _el$27.nextSibling, [_el$31, _co$7] = getNextMarker(_el$30.nextSibling), _el$32 = _el$26.nextSibling, _el$33 = _el$32.firstChild, _el$34 = _el$32.nextSibling, _el$37 = _el$34.firstChild, [_el$38, _co$8] = getNextMarker(_el$37.nextSibling), _el$39 = _el$38.nextSibling, [_el$40, _co$9] = getNextMarker(_el$39.nextSibling);
403
+ insert(_el$26, title, _el$29, _co$6);
404
+ insert(_el$26, () => strings.chartDataTable, _el$31, _co$7);
405
+ insert(_el$33, createComponent(For, {
230
406
  get each() {
231
407
  return tableData().columns;
232
408
  },
233
409
  children: (column) => (() => {
234
- var _el$45 = getNextElement(_tmpl$7);
235
- insert(_el$45, column);
236
- return _el$45;
410
+ var _el$53 = getNextElement(_tmpl$9);
411
+ insert(_el$53, column);
412
+ return _el$53;
237
413
  })()
238
414
  }));
239
- insert(_el$26, createComponent(For, {
415
+ insert(_el$34, createComponent(For, {
240
416
  get each() {
241
417
  return tableData().rows;
242
418
  },
243
419
  children: (row) => (() => {
244
- var _el$46 = getNextElement(_tmpl$8);
245
- insert(_el$46, createComponent(For, {
420
+ var _el$54 = getNextElement(_tmpl$0);
421
+ insert(_el$54, createComponent(For, {
246
422
  get each() {
247
423
  return tableData().columns;
248
424
  },
249
425
  children: (_column, index) => (() => {
250
- var _el$47 = getNextElement(_tmpl$9);
251
- insert(_el$47, () => String(row[index()] ?? ""));
252
- return _el$47;
426
+ var _el$55 = getNextElement(_tmpl$1);
427
+ insert(_el$55, () => String(row[index()] ?? ""));
428
+ return _el$55;
253
429
  })()
254
430
  }));
255
- return _el$46;
431
+ return _el$54;
256
432
  })()
257
- }), _el$30, _co$6);
258
- insert(_el$26, createComponent(Show, {
433
+ }), _el$38, _co$8);
434
+ insert(_el$34, createComponent(Show, {
259
435
  get when() {
260
436
  return tableData().rows.length === 0;
261
437
  },
262
438
  get children() {
263
- var _el$27 = getNextElement(_tmpl$3), _el$28 = _el$27.firstChild;
264
- insert(_el$28, () => strings.chartNoData);
265
- effect(() => setAttribute(_el$28, "colspan", Math.max(1, tableData().columns.length)));
266
- return _el$27;
439
+ var _el$35 = getNextElement(_tmpl$5), _el$36 = _el$35.firstChild;
440
+ insert(_el$36, () => strings.chartNoData);
441
+ effect(() => setAttribute(_el$36, "colspan", Math.max(1, tableData().columns.length)));
442
+ return _el$35;
267
443
  }
268
- }), _el$32, _co$7);
444
+ }), _el$40, _co$9);
269
445
  effect((_p$) => {
270
- var _v$4 = `w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$5 = isExpanded() ? void 0 : {
446
+ var _v$0 = `w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${isExpanded2() ? "flex-1 min-h-0" : ""}`, _v$1 = isExpanded2() ? void 0 : {
271
447
  height: params().height || "250px",
272
448
  "max-height": "70vh"
273
449
  };
274
- _v$4 !== _p$.e && className(_el$16, _p$.e = _v$4);
275
- _p$.t = style(_el$16, _v$5, _p$.t);
450
+ _v$0 !== _p$.e && className(_el$24, _p$.e = _v$0);
451
+ _p$.t = style(_el$24, _v$1, _p$.t);
276
452
  return _p$;
277
453
  }, {
278
454
  e: void 0,
279
455
  t: void 0
280
456
  });
281
- return _el$16;
457
+ return _el$24;
282
458
  }
283
- }), _el$44, _co$0);
459
+ }), _el$52, _co$10);
284
460
  var _ref$ = canvasRef;
285
- typeof _ref$ === "function" ? use(_ref$, _el$34) : canvasRef = _el$34;
286
- setAttribute(_el$34, "aria-describedby", descriptionId);
287
- insert(_el$33, createComponent(Show, {
461
+ typeof _ref$ === "function" ? use(_ref$, _el$42) : canvasRef = _el$42;
462
+ setAttribute(_el$42, "aria-describedby", descriptionId);
463
+ insert(_el$41, createComponent(Show, {
288
464
  get when() {
289
465
  return memo(() => !!isLoading())() && activeView() === "chart";
290
466
  },
291
467
  get children() {
292
- var _el$35 = getNextElement(_tmpl$5), _el$36 = _el$35.firstChild, _el$37 = _el$36.firstChild, _el$38 = _el$37.nextSibling;
293
- insert(_el$38, () => strings.chartLoading);
294
- return _el$35;
468
+ var _el$43 = getNextElement(_tmpl$7), _el$44 = _el$43.firstChild, _el$45 = _el$44.firstChild, _el$46 = _el$45.nextSibling;
469
+ insert(_el$46, () => strings.chartLoading);
470
+ return _el$43;
295
471
  }
296
- }), _el$40, _co$8);
472
+ }), _el$48, _co$0);
297
473
  effect((_p$) => {
298
- var _v$6 = `relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden p-4 group ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""} ${params().className || ""}`, _v$7 = strings.chartViewSelector, _v$8 = activeView() === "chart", _v$9 = `rounded px-2 py-1 text-xs font-medium transition-colors ${activeView() === "chart" ? "bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900" : "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"}`, _v$0 = activeView() === "data", _v$1 = `rounded px-2 py-1 text-xs font-medium transition-colors ${activeView() === "data" ? "bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900" : "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"}`, _v$10 = `relative w-full ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$11 = error() || activeView() === "data" ? {
474
+ var _v$10 = `relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden p-4 group ${isExpanded2() ? "flex-1 min-h-0 flex flex-col" : ""} ${params().className || ""}`, _v$11 = strings.chartViewSelector, _v$12 = activeView() === "chart", _v$13 = `rounded px-2 py-1 text-xs font-medium transition-colors ${activeView() === "chart" ? "bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900" : "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"}`, _v$14 = activeView() === "data", _v$15 = `rounded px-2 py-1 text-xs font-medium transition-colors ${activeView() === "data" ? "bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900" : "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"}`, _v$16 = `relative w-full ${isExpanded2() ? "flex-1 min-h-0" : ""}`, _v$17 = error() || activeView() === "data" ? {
299
475
  display: "none"
300
- } : isExpanded() ? {
476
+ } : isExpanded2() ? {
301
477
  height: "100%",
302
478
  display: "block"
303
479
  } : {
304
480
  height: params().height || "250px",
305
481
  display: "block"
306
- }, _v$12 = title(), _v$13 = activeView() !== "chart" || Boolean(error());
307
- _v$6 !== _p$.e && className(_el$, _p$.e = _v$6);
308
- _v$7 !== _p$.t && setAttribute(_el$6, "aria-label", _p$.t = _v$7);
309
- _v$8 !== _p$.a && setAttribute(_el$7, "aria-pressed", _p$.a = _v$8);
310
- _v$9 !== _p$.o && className(_el$7, _p$.o = _v$9);
311
- _v$0 !== _p$.i && setAttribute(_el$8, "aria-pressed", _p$.i = _v$0);
312
- _v$1 !== _p$.n && className(_el$8, _p$.n = _v$1);
313
- _v$10 !== _p$.s && className(_el$33, _p$.s = _v$10);
314
- _p$.h = style(_el$33, _v$11, _p$.h);
315
- _v$12 !== _p$.r && setAttribute(_el$34, "aria-label", _p$.r = _v$12);
316
- _v$13 !== _p$.d && setAttribute(_el$34, "aria-hidden", _p$.d = _v$13);
482
+ }, _v$18 = title(), _v$19 = activeView() !== "chart" || Boolean(error());
483
+ _v$10 !== _p$.e && className(_el$, _p$.e = _v$10);
484
+ _v$11 !== _p$.t && setAttribute(_el$6, "aria-label", _p$.t = _v$11);
485
+ _v$12 !== _p$.a && setAttribute(_el$7, "aria-pressed", _p$.a = _v$12);
486
+ _v$13 !== _p$.o && className(_el$7, _p$.o = _v$13);
487
+ _v$14 !== _p$.i && setAttribute(_el$8, "aria-pressed", _p$.i = _v$14);
488
+ _v$15 !== _p$.n && className(_el$8, _p$.n = _v$15);
489
+ _v$16 !== _p$.s && className(_el$41, _p$.s = _v$16);
490
+ _p$.h = style(_el$41, _v$17, _p$.h);
491
+ _v$18 !== _p$.r && setAttribute(_el$42, "aria-label", _p$.r = _v$18);
492
+ _v$19 !== _p$.d && setAttribute(_el$42, "aria-hidden", _p$.d = _v$19);
317
493
  return _p$;
318
494
  }, {
319
495
  e: void 0,