@seed-ship/mcp-ui-solid 6.17.0 → 6.18.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.
- package/CHANGELOG.md +28 -0
- package/README.md +50 -3
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/presentation.cjs +141 -0
- package/dist/adapters/presentation.cjs.map +1 -0
- package/dist/adapters/presentation.d.ts +68 -0
- package/dist/adapters/presentation.d.ts.map +1 -0
- package/dist/adapters/presentation.js +141 -0
- package/dist/adapters/presentation.js.map +1 -0
- package/dist/adapters.cjs +4 -0
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.d.cts +2 -0
- package/dist/adapters.d.ts +2 -0
- package/dist/adapters.js +4 -0
- package/dist/adapters.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +165 -65
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +168 -68
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ComponentToolbar.cjs.map +1 -1
- package/dist/components/ComponentToolbar.d.ts.map +1 -1
- package/dist/components/ComponentToolbar.js.map +1 -1
- package/dist/components/EditableLayoutContext.cjs +17 -0
- package/dist/components/EditableLayoutContext.cjs.map +1 -0
- package/dist/components/EditableLayoutContext.d.ts +5 -0
- package/dist/components/EditableLayoutContext.d.ts.map +1 -0
- package/dist/components/EditableLayoutContext.js +17 -0
- package/dist/components/EditableLayoutContext.js.map +1 -0
- package/dist/components/EditableUIResourceRenderer.cjs +87 -84
- package/dist/components/EditableUIResourceRenderer.cjs.map +1 -1
- package/dist/components/EditableUIResourceRenderer.d.ts.map +1 -1
- package/dist/components/EditableUIResourceRenderer.js +87 -84
- package/dist/components/EditableUIResourceRenderer.js.map +1 -1
- package/dist/components/ElicitationForm.cjs.map +1 -1
- package/dist/components/ElicitationForm.js.map +1 -1
- package/dist/components/FeedbackInline.cjs +0 -1
- package/dist/components/FeedbackInline.cjs.map +1 -1
- package/dist/components/FeedbackInline.js +0 -1
- package/dist/components/FeedbackInline.js.map +1 -1
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/GridRenderer.cjs +12 -6
- package/dist/components/GridRenderer.cjs.map +1 -1
- package/dist/components/GridRenderer.d.ts.map +1 -1
- package/dist/components/GridRenderer.js +13 -7
- package/dist/components/GridRenderer.js.map +1 -1
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/PresentationFeedback.cjs +0 -1
- package/dist/components/PresentationFeedback.cjs.map +1 -1
- package/dist/components/PresentationFeedback.js +0 -1
- package/dist/components/PresentationFeedback.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +37 -22
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +38 -23
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VerifiedText.cjs +0 -4
- package/dist/components/VerifiedText.cjs.map +1 -1
- package/dist/components/VerifiedText.d.ts.map +1 -1
- package/dist/components/VerifiedText.js +0 -4
- package/dist/components/VerifiedText.js.map +1 -1
- package/dist/components/chart-data-table.cjs +73 -0
- package/dist/components/chart-data-table.cjs.map +1 -0
- package/dist/components/chart-data-table.d.ts +23 -0
- package/dist/components/chart-data-table.d.ts.map +1 -0
- package/dist/components/chart-data-table.js +73 -0
- package/dist/components/chart-data-table.js.map +1 -0
- package/dist/context/MCPUIStringsContext.cjs +10 -9
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +17 -5
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +11 -10
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/hooks/createResponsiveGrid.cjs +37 -0
- package/dist/hooks/createResponsiveGrid.cjs.map +1 -0
- package/dist/hooks/createResponsiveGrid.d.ts +6 -0
- package/dist/hooks/createResponsiveGrid.d.ts.map +1 -0
- package/dist/hooks/createResponsiveGrid.js +37 -0
- package/dist/hooks/createResponsiveGrid.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-ui-spec/dist/schemas.cjs +13 -1
- package/dist/mcp-ui-spec/dist/schemas.cjs.map +1 -1
- package/dist/mcp-ui-spec/dist/schemas.js +13 -1
- package/dist/mcp-ui-spec/dist/schemas.js.map +1 -1
- package/dist/services/chat-bus.cjs.map +1 -1
- package/dist/services/chat-bus.d.ts.map +1 -1
- package/dist/services/chat-bus.js.map +1 -1
- package/dist/services/chat-prompt-controller.cjs.map +1 -1
- package/dist/services/chat-prompt-controller.d.ts.map +1 -1
- package/dist/services/chat-prompt-controller.js.map +1 -1
- package/dist/services/component-registry.cjs +162 -22
- package/dist/services/component-registry.cjs.map +1 -1
- package/dist/services/component-registry.d.ts +6 -3
- package/dist/services/component-registry.d.ts.map +1 -1
- package/dist/services/component-registry.js +162 -22
- package/dist/services/component-registry.js.map +1 -1
- package/dist/services/telemetry.cjs +0 -1
- package/dist/services/telemetry.cjs.map +1 -1
- package/dist/services/telemetry.js +0 -1
- package/dist/services/telemetry.js.map +1 -1
- package/dist/services/validation.cjs +21 -7
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +21 -7
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +43 -8
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +43 -8
- package/dist/types.d.ts +43 -8
- package/docs/briefs/VISUALIZATION-FOUNDATION-2026-09-14.md +105 -0
- package/package.json +4 -4
- package/src/adapters/index.ts +18 -0
- package/src/adapters/presentation.test.ts +114 -0
- package/src/adapters/presentation.ts +229 -0
- package/src/components/ChartJSRenderer.test.tsx +325 -0
- package/src/components/ChartJSRenderer.tsx +162 -27
- package/src/components/ChatPrompt.test.tsx +1 -1
- package/src/components/ComponentToolbar.tsx +1 -1
- package/src/components/EditableLayoutContext.tsx +12 -0
- package/src/components/EditableUIResourceRenderer.tsx +11 -8
- package/src/components/ElicitationForm.tsx +1 -1
- package/src/components/FeedbackInline.tsx +1 -1
- package/src/components/GraphRenderer.test.tsx +1 -2
- package/src/components/GraphRenderer.tsx +0 -2
- package/src/components/GridRenderer.tsx +6 -4
- package/src/components/MapRenderer.tsx +0 -3
- package/src/components/PresentationFeedback.tsx +1 -1
- package/src/components/ResponsiveGrid.test.tsx +166 -0
- package/src/components/TableRenderer.pagination.test.tsx +31 -0
- package/src/components/UIResourceRenderer.tsx +14 -9
- package/src/components/VerifiedText.tsx +0 -5
- package/src/components/chart-data-table.ts +97 -0
- package/src/context/MCPUIStringsContext.test.tsx +60 -0
- package/src/context/MCPUIStringsContext.tsx +31 -12
- package/src/hooks/createResponsiveGrid.ts +41 -0
- package/src/services/chat-bus.test.ts +1 -1
- package/src/services/chat-bus.ts +0 -2
- package/src/services/chat-prompt-controller.ts +0 -8
- package/src/services/component-registry.test.ts +81 -2
- package/src/services/component-registry.ts +167 -23
- package/src/services/telemetry.ts +1 -1
- package/src/services/validation.test.ts +1 -14
- package/src/services/validation.ts +23 -6
- package/src/services/visualization-validation.test.ts +42 -0
- package/src/types/index.ts +50 -9
- package/src/types/visualization-contracts.test.ts +66 -0
- package/src/utils/perf.test.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { delegateEvents, createComponent, getNextElement, getNextMarker, insert, runHydrationEvents, mergeProps,
|
|
2
|
-
import { createSignal, createEffect, onCleanup, Show } from "solid-js";
|
|
3
|
-
import {
|
|
1
|
+
import { delegateEvents, createComponent, getNextElement, getNextMarker, insert, effect, setProperty, runHydrationEvents, setAttribute, mergeProps, memo, className, style, template, use } from "solid-js/web";
|
|
2
|
+
import { createSignal, createMemo, createUniqueId, createEffect, onCleanup, Show, For } from "solid-js";
|
|
3
|
+
import { ExpandableWrapper, useExpanded } from "./ExpandableWrapper.js";
|
|
4
4
|
import { DegradedFallback } from "./DegradedFallback.js";
|
|
5
|
-
import {
|
|
5
|
+
import { chartToDataTable } from "./chart-data-table.js";
|
|
6
6
|
import { useTelemetry } from "../context/MCPUITelemetryContext.js";
|
|
7
|
-
|
|
7
|
+
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
8
|
+
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"title="Download PNG"aria-label="Download chart as PNG"><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">Loading chart...`), _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">`);
|
|
8
9
|
let ChartJS = null;
|
|
9
10
|
let chartJSLoadPromise = null;
|
|
10
11
|
const loadChartJS = async () => {
|
|
@@ -28,14 +29,20 @@ async function isChartJSAvailable() {
|
|
|
28
29
|
return false;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
const ContextAwareChartLayout = (props) => props.render(useExpanded());
|
|
31
33
|
const ChartJSRenderer = (props) => {
|
|
32
34
|
const [isLoading, setIsLoading] = createSignal(true);
|
|
33
35
|
const [error, setError] = createSignal();
|
|
36
|
+
const [activeView, setActiveView] = createSignal("chart");
|
|
34
37
|
let canvasRef;
|
|
35
38
|
let chartInstance;
|
|
39
|
+
let renderVersion = 0;
|
|
36
40
|
const params = () => props.component.params;
|
|
37
|
-
const
|
|
41
|
+
const tableData = createMemo(() => chartToDataTable(params()));
|
|
38
42
|
const telemetry = useTelemetry();
|
|
43
|
+
const strings = useMCPUIStrings();
|
|
44
|
+
const descriptionId = createUniqueId();
|
|
45
|
+
const title = () => params().title || strings.chartView;
|
|
39
46
|
const exportEnabled = () => params().exportable !== false;
|
|
40
47
|
const copyDataJSON = () => JSON.stringify({
|
|
41
48
|
type: params().type,
|
|
@@ -53,10 +60,12 @@ const ChartJSRenderer = (props) => {
|
|
|
53
60
|
var _a, _b, _c, _d, _e, _f;
|
|
54
61
|
if (!canvasRef) return;
|
|
55
62
|
const chartParams = params();
|
|
63
|
+
const version = ++renderVersion;
|
|
56
64
|
setIsLoading(true);
|
|
57
65
|
setError(void 0);
|
|
58
66
|
try {
|
|
59
67
|
const Chart = await loadChartJS();
|
|
68
|
+
if (version !== renderVersion || !canvasRef) return;
|
|
60
69
|
if (chartInstance) {
|
|
61
70
|
chartInstance.destroy();
|
|
62
71
|
chartInstance = null;
|
|
@@ -102,6 +111,7 @@ const ChartJSRenderer = (props) => {
|
|
|
102
111
|
});
|
|
103
112
|
setIsLoading(false);
|
|
104
113
|
} catch (err) {
|
|
114
|
+
if (version !== renderVersion) return;
|
|
105
115
|
const error2 = err instanceof Error ? err : new Error("Chart rendering failed");
|
|
106
116
|
setError(error2.message);
|
|
107
117
|
setIsLoading(false);
|
|
@@ -115,7 +125,15 @@ const ChartJSRenderer = (props) => {
|
|
|
115
125
|
(_f = props.onError) == null ? void 0 : _f.call(props, error2);
|
|
116
126
|
}
|
|
117
127
|
});
|
|
128
|
+
createEffect(() => {
|
|
129
|
+
if (activeView() !== "chart" || !chartInstance) return;
|
|
130
|
+
queueMicrotask(() => {
|
|
131
|
+
var _a;
|
|
132
|
+
return (_a = chartInstance == null ? void 0 : chartInstance.resize) == null ? void 0 : _a.call(chartInstance);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
118
135
|
onCleanup(() => {
|
|
136
|
+
renderVersion += 1;
|
|
119
137
|
if (chartInstance) {
|
|
120
138
|
chartInstance.destroy();
|
|
121
139
|
chartInstance = null;
|
|
@@ -123,7 +141,7 @@ const ChartJSRenderer = (props) => {
|
|
|
123
141
|
});
|
|
124
142
|
return createComponent(ExpandableWrapper, {
|
|
125
143
|
get title() {
|
|
126
|
-
return
|
|
144
|
+
return title();
|
|
127
145
|
},
|
|
128
146
|
get copyData() {
|
|
129
147
|
return copyDataJSON();
|
|
@@ -133,80 +151,162 @@ const ChartJSRenderer = (props) => {
|
|
|
133
151
|
return props.toolbarVariant;
|
|
134
152
|
},
|
|
135
153
|
get children() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
},
|
|
141
|
-
get children() {
|
|
142
|
-
var _el$2 = getNextElement(_tmpl$3), _el$5 = _el$2.firstChild, [_el$6, _co$] = getNextMarker(_el$5.nextSibling), _el$7 = _el$6.nextSibling, [_el$8, _co$2] = getNextMarker(_el$7.nextSibling);
|
|
143
|
-
insert(_el$2, createComponent(Show, {
|
|
154
|
+
return createComponent(ContextAwareChartLayout, {
|
|
155
|
+
render: (isExpanded) => (() => {
|
|
156
|
+
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$38 = _el$10.nextSibling, [_el$39, _co$9] = getNextMarker(_el$38.nextSibling), _el$40 = _el$39.nextSibling, [_el$41, _co$0] = getNextMarker(_el$40.nextSibling), _el$33 = _el$41.nextSibling, _el$34 = _el$33.firstChild, _el$36 = _el$34.nextSibling, [_el$37, _co$8] = getNextMarker(_el$36.nextSibling);
|
|
157
|
+
insert(_el$3, createComponent(Show, {
|
|
144
158
|
get when() {
|
|
145
159
|
return params().title;
|
|
146
160
|
},
|
|
147
161
|
get children() {
|
|
148
|
-
var _el$
|
|
149
|
-
insert(_el$
|
|
150
|
-
return _el$
|
|
162
|
+
var _el$4 = getNextElement(_tmpl$);
|
|
163
|
+
insert(_el$4, () => params().title);
|
|
164
|
+
return _el$4;
|
|
151
165
|
}
|
|
152
|
-
})
|
|
153
|
-
|
|
166
|
+
}));
|
|
167
|
+
_el$7.$$click = () => setActiveView("chart");
|
|
168
|
+
insert(_el$7, () => strings.chartView);
|
|
169
|
+
_el$8.$$click = () => setActiveView("data");
|
|
170
|
+
insert(_el$8, () => strings.chartDataView);
|
|
171
|
+
insert(_el$5, createComponent(Show, {
|
|
154
172
|
get when() {
|
|
155
173
|
return exportEnabled();
|
|
156
174
|
},
|
|
157
175
|
get children() {
|
|
158
|
-
var _el$
|
|
159
|
-
_el$
|
|
176
|
+
var _el$9 = getNextElement(_tmpl$2);
|
|
177
|
+
_el$9.$$click = handleExportPNG;
|
|
178
|
+
effect(() => setProperty(_el$9, "disabled", activeView() !== "chart" || isLoading() || Boolean(error())));
|
|
160
179
|
runHydrationEvents();
|
|
161
|
-
return _el$
|
|
180
|
+
return _el$9;
|
|
162
181
|
}
|
|
163
|
-
}), _el$
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
},
|
|
171
|
-
get children() {
|
|
172
|
-
return getNextElement(_tmpl$4);
|
|
173
|
-
}
|
|
174
|
-
}), _el$13, _co$4);
|
|
175
|
-
insert(_el$, createComponent(Show, {
|
|
176
|
-
get when() {
|
|
177
|
-
return error();
|
|
178
|
-
},
|
|
179
|
-
get children() {
|
|
180
|
-
return createComponent(DegradedFallback, mergeProps({
|
|
181
|
-
get message() {
|
|
182
|
-
return `Chart rendering failed: ${error()}`;
|
|
182
|
+
}), _el$1, _co$);
|
|
183
|
+
setAttribute(_el$10, "id", descriptionId);
|
|
184
|
+
insert(_el$10, title, _el$13, _co$2);
|
|
185
|
+
insert(_el$10, () => strings.chartDataSummary, _el$15, _co$3);
|
|
186
|
+
insert(_el$, createComponent(Show, {
|
|
187
|
+
get when() {
|
|
188
|
+
return memo(() => !!error())() && activeView() === "chart";
|
|
183
189
|
},
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
190
|
+
get children() {
|
|
191
|
+
return createComponent(DegradedFallback, mergeProps({
|
|
192
|
+
get message() {
|
|
193
|
+
return `Chart rendering failed: ${error()}`;
|
|
194
|
+
},
|
|
195
|
+
caption: "Showing the chart data as a table — the interactive chart is unavailable."
|
|
196
|
+
}, tableData));
|
|
197
|
+
}
|
|
198
|
+
}), _el$39, _co$9);
|
|
199
|
+
insert(_el$, createComponent(Show, {
|
|
200
|
+
get when() {
|
|
201
|
+
return activeView() === "data";
|
|
202
|
+
},
|
|
203
|
+
get children() {
|
|
204
|
+
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);
|
|
205
|
+
insert(_el$18, title, _el$21, _co$4);
|
|
206
|
+
insert(_el$18, () => strings.chartDataTable, _el$23, _co$5);
|
|
207
|
+
insert(_el$25, createComponent(For, {
|
|
208
|
+
get each() {
|
|
209
|
+
return tableData().columns;
|
|
210
|
+
},
|
|
211
|
+
children: (column) => (() => {
|
|
212
|
+
var _el$42 = getNextElement(_tmpl$7);
|
|
213
|
+
insert(_el$42, column);
|
|
214
|
+
return _el$42;
|
|
215
|
+
})()
|
|
216
|
+
}));
|
|
217
|
+
insert(_el$26, createComponent(For, {
|
|
218
|
+
get each() {
|
|
219
|
+
return tableData().rows;
|
|
220
|
+
},
|
|
221
|
+
children: (row) => (() => {
|
|
222
|
+
var _el$43 = getNextElement(_tmpl$8);
|
|
223
|
+
insert(_el$43, createComponent(For, {
|
|
224
|
+
get each() {
|
|
225
|
+
return tableData().columns;
|
|
226
|
+
},
|
|
227
|
+
children: (_column, index) => (() => {
|
|
228
|
+
var _el$44 = getNextElement(_tmpl$9);
|
|
229
|
+
insert(_el$44, () => String(row[index()] ?? ""));
|
|
230
|
+
return _el$44;
|
|
231
|
+
})()
|
|
232
|
+
}));
|
|
233
|
+
return _el$43;
|
|
234
|
+
})()
|
|
235
|
+
}), _el$30, _co$6);
|
|
236
|
+
insert(_el$26, createComponent(Show, {
|
|
237
|
+
get when() {
|
|
238
|
+
return tableData().rows.length === 0;
|
|
239
|
+
},
|
|
240
|
+
get children() {
|
|
241
|
+
var _el$27 = getNextElement(_tmpl$3), _el$28 = _el$27.firstChild;
|
|
242
|
+
insert(_el$28, () => strings.chartNoData);
|
|
243
|
+
effect(() => setAttribute(_el$28, "colspan", Math.max(1, tableData().columns.length)));
|
|
244
|
+
return _el$27;
|
|
245
|
+
}
|
|
246
|
+
}), _el$32, _co$7);
|
|
247
|
+
effect((_p$) => {
|
|
248
|
+
var _v$ = `w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$2 = isExpanded() ? void 0 : {
|
|
249
|
+
height: params().height || "250px",
|
|
250
|
+
"max-height": "70vh"
|
|
251
|
+
};
|
|
252
|
+
_v$ !== _p$.e && className(_el$16, _p$.e = _v$);
|
|
253
|
+
_p$.t = style(_el$16, _v$2, _p$.t);
|
|
254
|
+
return _p$;
|
|
255
|
+
}, {
|
|
256
|
+
e: void 0,
|
|
257
|
+
t: void 0
|
|
258
|
+
});
|
|
259
|
+
return _el$16;
|
|
260
|
+
}
|
|
261
|
+
}), _el$41, _co$0);
|
|
262
|
+
var _ref$ = canvasRef;
|
|
263
|
+
typeof _ref$ === "function" ? use(_ref$, _el$34) : canvasRef = _el$34;
|
|
264
|
+
setAttribute(_el$34, "aria-describedby", descriptionId);
|
|
265
|
+
insert(_el$33, createComponent(Show, {
|
|
266
|
+
get when() {
|
|
267
|
+
return memo(() => !!isLoading())() && activeView() === "chart";
|
|
268
|
+
},
|
|
269
|
+
get children() {
|
|
270
|
+
return getNextElement(_tmpl$5);
|
|
271
|
+
}
|
|
272
|
+
}), _el$37, _co$8);
|
|
273
|
+
effect((_p$) => {
|
|
274
|
+
var _v$3 = `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$4 = strings.chartViewSelector, _v$5 = activeView() === "chart", _v$6 = `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$7 = activeView() === "data", _v$8 = `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$9 = `relative w-full ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$0 = error() || activeView() === "data" ? {
|
|
275
|
+
display: "none"
|
|
276
|
+
} : isExpanded() ? {
|
|
277
|
+
height: "100%",
|
|
278
|
+
display: "block"
|
|
279
|
+
} : {
|
|
280
|
+
height: params().height || "250px",
|
|
281
|
+
display: "block"
|
|
282
|
+
}, _v$1 = title(), _v$10 = activeView() !== "chart" || Boolean(error());
|
|
283
|
+
_v$3 !== _p$.e && className(_el$, _p$.e = _v$3);
|
|
284
|
+
_v$4 !== _p$.t && setAttribute(_el$6, "aria-label", _p$.t = _v$4);
|
|
285
|
+
_v$5 !== _p$.a && setAttribute(_el$7, "aria-pressed", _p$.a = _v$5);
|
|
286
|
+
_v$6 !== _p$.o && className(_el$7, _p$.o = _v$6);
|
|
287
|
+
_v$7 !== _p$.i && setAttribute(_el$8, "aria-pressed", _p$.i = _v$7);
|
|
288
|
+
_v$8 !== _p$.n && className(_el$8, _p$.n = _v$8);
|
|
289
|
+
_v$9 !== _p$.s && className(_el$33, _p$.s = _v$9);
|
|
290
|
+
_p$.h = style(_el$33, _v$0, _p$.h);
|
|
291
|
+
_v$1 !== _p$.r && setAttribute(_el$34, "aria-label", _p$.r = _v$1);
|
|
292
|
+
_v$10 !== _p$.d && setAttribute(_el$34, "aria-hidden", _p$.d = _v$10);
|
|
293
|
+
return _p$;
|
|
294
|
+
}, {
|
|
295
|
+
e: void 0,
|
|
296
|
+
t: void 0,
|
|
297
|
+
a: void 0,
|
|
298
|
+
o: void 0,
|
|
299
|
+
i: void 0,
|
|
300
|
+
n: void 0,
|
|
301
|
+
s: void 0,
|
|
302
|
+
h: void 0,
|
|
303
|
+
r: void 0,
|
|
304
|
+
d: void 0
|
|
305
|
+
});
|
|
306
|
+
runHydrationEvents();
|
|
307
|
+
return _el$;
|
|
308
|
+
})()
|
|
208
309
|
});
|
|
209
|
-
return _el$;
|
|
210
310
|
}
|
|
211
311
|
});
|
|
212
312
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartJSRenderer.js","sources":["../../src/components/ChartJSRenderer.tsx"],"sourcesContent":["/**\n * ChartJSRenderer - Native Chart.js rendering\n * Sprint 4: State & Charts\n *\n * Requires chart.js peer dependency:\n * ```\n * pnpm add chart.js\n * ```\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show } from 'solid-js';\nimport type { UIComponent, ChartComponentParams } from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { chartToDegradedTable } from '../utils/degraded-projections';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\n\n// Lazy load Chart.js to avoid bundling if not used\nlet ChartJS: any = null;\nlet chartJSLoadPromise: Promise<any> | null = null;\n\nconst loadChartJS = async () => {\n if (ChartJS) return ChartJS;\n\n if (!chartJSLoadPromise) {\n chartJSLoadPromise = import('chart.js/auto')\n .then((module) => {\n ChartJS = module.default || module.Chart;\n return ChartJS;\n })\n .catch((err) => {\n chartJSLoadPromise = null;\n throw err;\n });\n }\n\n return chartJSLoadPromise;\n};\n\n/**\n * Check if Chart.js is available\n */\nexport async function isChartJSAvailable(): Promise<boolean> {\n try {\n await loadChartJS();\n return true;\n } catch {\n return false;\n }\n}\n\nexport interface ChartJSRendererProps {\n /**\n * UIComponent with chart params\n */\n component: UIComponent;\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\n/**\n * Native Chart.js renderer component\n *\n * @example\n * ```tsx\n * const chartComponent: UIComponent = {\n * id: 'revenue-chart',\n * type: 'chart',\n * position: { colStart: 1, colSpan: 6 },\n * params: {\n * type: 'bar',\n * title: 'Monthly Revenue',\n * data: {\n * labels: ['Jan', 'Feb', 'Mar'],\n * datasets: [{ label: 'Revenue', data: [100, 200, 150] }]\n * },\n * renderer: 'native',\n * },\n * }\n * <ChartJSRenderer component={chartComponent} />\n * ```\n */\nexport const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {\n const [isLoading, setIsLoading] = createSignal(true);\n const [error, setError] = createSignal<string>();\n let canvasRef: HTMLCanvasElement | undefined;\n let chartInstance: any;\n\n const params = () => props.component.params as ChartComponentParams;\n const isExpanded = useExpanded();\n const telemetry = useTelemetry();\n\n // v6.1.0 — export visibility :\n // - undefined / true → button shown (new default, was opt-in)\n // - false → button hidden (explicit opt-out, unchanged)\n const exportEnabled = () => params().exportable !== false;\n\n // v6.1.0 — copy data for the ExpandableWrapper modal-header copy button.\n // Lazy-stringified each time the button is clicked.\n const copyDataJSON = () => JSON.stringify({ type: params().type, data: params().data }, null, 2);\n\n // Chart PNG export\n const handleExportPNG = () => {\n if (!canvasRef) return;\n const url = canvasRef.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = `${(params().title || 'chart').replace(/\\s+/g, '-').toLowerCase()}.png`;\n a.click();\n };\n\n // Create/update chart when params change\n createEffect(async () => {\n if (!canvasRef) return;\n\n // Access params to track dependencies\n const chartParams = params();\n\n setIsLoading(true);\n setError(undefined);\n\n try {\n const Chart = await loadChartJS();\n\n // Destroy previous instance\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n\n // Build options, merging time-axis config if present (v3.1.0)\n const baseOptions: any = {\n responsive: true,\n maintainAspectRatio: false,\n ...chartParams.options,\n plugins: {\n ...chartParams.options?.plugins,\n legend: {\n display: true,\n position: 'bottom',\n ...chartParams.options?.plugins?.legend,\n },\n },\n };\n\n // Time-series axis (v3.1.0)\n if (chartParams.timeAxis) {\n const ta = chartParams.timeAxis;\n baseOptions.scales = {\n ...baseOptions.scales,\n x: {\n ...baseOptions.scales?.x,\n type: 'time',\n time: {\n parser: ta.parser,\n unit: ta.unit,\n tooltipFormat: ta.tooltipFormat,\n },\n ...(ta.min ? { min: ta.min } : {}),\n ...(ta.max ? { max: ta.max } : {}),\n },\n };\n }\n\n // Create new chart\n chartInstance = new Chart(canvasRef, {\n type: chartParams.type,\n data: chartParams.data,\n options: baseOptions,\n });\n\n setIsLoading(false);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Chart rendering failed');\n setError(error.message);\n setIsLoading(false);\n // Fallback ladder (P2.5): record the failure so it's observable, then\n // degrade to the series table below instead of a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: error.message,\n id: props.component?.id ?? '',\n componentType: 'chart',\n ts: Date.now(),\n });\n props.onError?.(error);\n }\n });\n\n // Cleanup on unmount\n onCleanup(() => {\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={params().title || 'Chart'}\n copyData={copyDataJSON()}\n copyLabel=\"Copy chart data (JSON)\"\n toolbarVariant={props.toolbarVariant}\n >\n <div\n class={`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 ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}\n >\n <Show when={params().title || exportEnabled()}>\n <div class=\"flex items-center justify-between mb-3 flex-shrink-0\">\n <Show when={params().title}>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params().title}</h3>\n </Show>\n <Show when={exportEnabled()}>\n <button\n onClick={handleExportPNG}\n class=\"opacity-0 group-hover: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\"\n title=\"Download PNG\"\n aria-label=\"Download chart as PNG\"\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n 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\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </Show>\n\n <Show when={isLoading()}>\n <div class=\"absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80\">\n <div class=\"flex flex-col items-center gap-2\">\n <div class=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\" />\n <span class=\"text-sm text-gray-500 dark:text-gray-400\">Loading chart...</span>\n </div>\n </div>\n </Show>\n\n {/* Fallback ladder (P2.5): degrade to a series table on render error\n instead of a bare \"Chart Error\" message. */}\n <Show when={error()}>\n <DegradedFallback\n message={`Chart rendering failed: ${error()}`}\n caption=\"Showing the chart data as a table — the interactive chart is unavailable.\"\n {...chartToDegradedTable(params() ?? {})}\n />\n </Show>\n\n <div\n class={`w-full ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n error()\n ? { display: 'none' }\n : isExpanded()\n ? { height: '100%', display: 'block' }\n : { height: params().height || '250px', display: 'block' }\n }\n >\n <canvas ref={canvasRef} />\n </div>\n </div>\n </ExpandableWrapper>\n );\n};\n"],"names":["ChartJS","chartJSLoadPromise","loadChartJS","then","module","default","Chart","catch","err","isChartJSAvailable","ChartJSRenderer","props","isLoading","setIsLoading","createSignal","error","setError","canvasRef","chartInstance","params","component","isExpanded","useExpanded","telemetry","useTelemetry","exportEnabled","exportable","copyDataJSON","JSON","stringify","type","data","handleExportPNG","url","toDataURL","a","document","createElement","href","download","title","replace","toLowerCase","click","createEffect","chartParams","undefined","destroy","baseOptions","responsive","maintainAspectRatio","options","plugins","legend","display","position","timeAxis","ta","scales","x","time","parser","unit","tooltipFormat","min","max","Error","message","dispatch","errorMessage","id","componentType","ts","Date","now","onError","onCleanup","_$createComponent","ExpandableWrapper","copyData","copyLabel","toolbarVariant","children","_el$","_$getNextElement","_tmpl$5","_el$10","firstChild","_el$11","_co$3","_$getNextMarker","nextSibling","_el$12","_el$13","_co$4","_el$14","_el$15","_co$5","_el$0","_el$1","_$insert","Show","when","_el$2","_tmpl$3","_el$5","_el$6","_co$","_el$7","_el$8","_co$2","_el$3","_tmpl$","_el$4","_tmpl$2","$$click","_$runHydrationEvents","_tmpl$4","DegradedFallback","_$mergeProps","caption","chartToDegradedTable","_ref$","_$use","_$effect","_p$","_v$","_v$2","_v$3","height","e","_$className","t","_$style","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChartJSRenderer.js","sources":["../../src/components/ChartJSRenderer.tsx"],"sourcesContent":["/**\n * ChartJSRenderer - Native Chart.js rendering\n * Sprint 4: State & Charts\n *\n * Requires chart.js peer dependency:\n * ```\n * pnpm add chart.js\n * ```\n */\n\nimport {\n Component,\n For,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n createSignal,\n Show,\n} from 'solid-js';\nimport type { Accessor, JSX } from 'solid-js';\nimport type { UIComponent, ChartComponentParams } from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { chartToDataTable } from './chart-data-table';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext';\n\n// Lazy load Chart.js to avoid bundling if not used\nlet ChartJS: any = null;\nlet chartJSLoadPromise: Promise<any> | null = null;\n\nconst loadChartJS = async () => {\n if (ChartJS) return ChartJS;\n\n if (!chartJSLoadPromise) {\n chartJSLoadPromise = import('chart.js/auto')\n .then((module) => {\n ChartJS = module.default || module.Chart;\n return ChartJS;\n })\n .catch((err) => {\n chartJSLoadPromise = null;\n throw err;\n });\n }\n\n return chartJSLoadPromise;\n};\n\n/**\n * Check if Chart.js is available\n */\nexport async function isChartJSAvailable(): Promise<boolean> {\n try {\n await loadChartJS();\n return true;\n } catch {\n return false;\n }\n}\n\nexport interface ChartJSRendererProps {\n /**\n * UIComponent with chart params\n */\n component: UIComponent;\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\nconst ContextAwareChartLayout: Component<{\n render: (isExpanded: Accessor<boolean>) => JSX.Element;\n}> = (props) => props.render(useExpanded());\n\n/**\n * Native Chart.js renderer component\n *\n * @example\n * ```tsx\n * const chartComponent: UIComponent = {\n * id: 'revenue-chart',\n * type: 'chart',\n * position: { colStart: 1, colSpan: 6 },\n * params: {\n * type: 'bar',\n * title: 'Monthly Revenue',\n * data: {\n * labels: ['Jan', 'Feb', 'Mar'],\n * datasets: [{ label: 'Revenue', data: [100, 200, 150] }]\n * },\n * renderer: 'native',\n * },\n * }\n * <ChartJSRenderer component={chartComponent} />\n * ```\n */\nexport const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {\n const [isLoading, setIsLoading] = createSignal(true);\n const [error, setError] = createSignal<string>();\n const [activeView, setActiveView] = createSignal<'chart' | 'data'>('chart');\n let canvasRef: HTMLCanvasElement | undefined;\n let chartInstance: any;\n let renderVersion = 0;\n\n const params = () => props.component.params as ChartComponentParams;\n const tableData = createMemo(() => chartToDataTable(params()));\n const telemetry = useTelemetry();\n const strings = useMCPUIStrings();\n const descriptionId = createUniqueId();\n const title = () => params().title || strings.chartView;\n\n // v6.1.0 — export visibility :\n // - undefined / true → button shown (new default, was opt-in)\n // - false → button hidden (explicit opt-out, unchanged)\n const exportEnabled = () => params().exportable !== false;\n\n // v6.1.0 — copy data for the ExpandableWrapper modal-header copy button.\n // Lazy-stringified each time the button is clicked.\n const copyDataJSON = () => JSON.stringify({ type: params().type, data: params().data }, null, 2);\n\n // Chart PNG export\n const handleExportPNG = () => {\n if (!canvasRef) return;\n const url = canvasRef.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = `${(params().title || 'chart').replace(/\\s+/g, '-').toLowerCase()}.png`;\n a.click();\n };\n\n // Create/update chart when params change\n createEffect(async () => {\n if (!canvasRef) return;\n\n // Access params to track dependencies\n const chartParams = params();\n const version = ++renderVersion;\n\n setIsLoading(true);\n setError(undefined);\n\n try {\n const Chart = await loadChartJS();\n\n // A newer prop update or an unmount superseded this async render.\n if (version !== renderVersion || !canvasRef) return;\n\n // Destroy previous instance\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n\n // Build options, merging time-axis config if present (v3.1.0)\n const baseOptions: any = {\n responsive: true,\n maintainAspectRatio: false,\n ...chartParams.options,\n plugins: {\n ...chartParams.options?.plugins,\n legend: {\n display: true,\n position: 'bottom',\n ...chartParams.options?.plugins?.legend,\n },\n },\n };\n\n // Time-series axis (v3.1.0)\n if (chartParams.timeAxis) {\n const ta = chartParams.timeAxis;\n baseOptions.scales = {\n ...baseOptions.scales,\n x: {\n ...baseOptions.scales?.x,\n type: 'time',\n time: {\n parser: ta.parser,\n unit: ta.unit,\n tooltipFormat: ta.tooltipFormat,\n },\n ...(ta.min ? { min: ta.min } : {}),\n ...(ta.max ? { max: ta.max } : {}),\n },\n };\n }\n\n // Create new chart\n chartInstance = new Chart(canvasRef, {\n type: chartParams.type,\n data: chartParams.data,\n options: baseOptions,\n });\n\n setIsLoading(false);\n } catch (err) {\n if (version !== renderVersion) return;\n const error = err instanceof Error ? err : new Error('Chart rendering failed');\n setError(error.message);\n setIsLoading(false);\n // Fallback ladder (P2.5): record the failure so it's observable, then\n // degrade to the series table below instead of a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: error.message,\n id: props.component?.id ?? '',\n componentType: 'chart',\n ts: Date.now(),\n });\n props.onError?.(error);\n }\n });\n\n // Chart.js may measure a zero-sized canvas while the data view is visible.\n // Resize once Solid has revealed it again.\n createEffect(() => {\n if (activeView() !== 'chart' || !chartInstance) return;\n queueMicrotask(() => chartInstance?.resize?.());\n });\n\n // Cleanup on unmount\n onCleanup(() => {\n renderVersion += 1;\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={title()}\n copyData={copyDataJSON()}\n copyLabel=\"Copy chart data (JSON)\"\n toolbarVariant={props.toolbarVariant}\n >\n <ContextAwareChartLayout\n render={(isExpanded) => (\n <div\n class={`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 ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n } ${params().className || ''}`}\n >\n <div class=\"flex items-center justify-between gap-3 mb-3 flex-shrink-0\">\n <div class=\"min-w-0\">\n <Show when={params().title}>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params().title}</h3>\n </Show>\n </div>\n <div class=\"flex items-center gap-2\">\n <div\n class=\"inline-flex rounded-md border border-gray-200 p-0.5 dark:border-gray-600\"\n role=\"group\"\n aria-label={strings.chartViewSelector}\n >\n <button\n type=\"button\"\n aria-pressed={activeView() === 'chart'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'chart'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('chart')}\n >\n {strings.chartView}\n </button>\n <button\n type=\"button\"\n aria-pressed={activeView() === 'data'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'data'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('data')}\n >\n {strings.chartDataView}\n </button>\n </div>\n <Show when={exportEnabled()}>\n <button\n type=\"button\"\n onClick={handleExportPNG}\n disabled={activeView() !== 'chart' || isLoading() || Boolean(error())}\n 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\"\n title=\"Download PNG\"\n aria-label=\"Download chart as PNG\"\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n 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\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </div>\n\n <p id={descriptionId} class=\"sr-only\">\n {title()}. {strings.chartDataSummary}\n </p>\n\n {/* Fallback ladder (P2.5): degrade to a series table on render error\n instead of a bare \"Chart Error\" message. */}\n <Show when={error() && activeView() === 'chart'}>\n <DegradedFallback\n message={`Chart rendering failed: ${error()}`}\n caption=\"Showing the chart data as a table — the interactive chart is unavailable.\"\n {...tableData()}\n />\n </Show>\n\n <Show when={activeView() === 'data'}>\n <div\n class={`w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${\n isExpanded() ? 'flex-1 min-h-0' : ''\n }`}\n style={\n isExpanded()\n ? undefined\n : { height: params().height || '250px', 'max-height': '70vh' }\n }\n >\n <table class=\"w-full border-collapse text-left text-sm\">\n <caption class=\"sr-only\">\n {title()} — {strings.chartDataTable}\n </caption>\n <thead class=\"bg-gray-50 dark:bg-gray-900/40\">\n <tr>\n <For each={tableData().columns}>\n {(column) => (\n <th scope=\"col\" class=\"px-3 py-2 font-medium text-gray-900 dark:text-gray-100\">\n {column}\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={tableData().rows}>\n {(row) => (\n <tr class=\"border-t border-gray-100 dark:border-gray-700\">\n <For each={tableData().columns}>\n {(_column, index) => (\n <td class=\"px-3 py-2 text-gray-700 dark:text-gray-300\">\n {String(row[index()] ?? '')}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n <Show when={tableData().rows.length === 0}>\n <tr>\n <td\n colSpan={Math.max(1, tableData().columns.length)}\n class=\"px-3 py-6 text-center text-gray-500 dark:text-gray-400\"\n >\n {strings.chartNoData}\n </td>\n </tr>\n </Show>\n </tbody>\n </table>\n </div>\n </Show>\n\n <div\n class={`relative w-full ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n error() || activeView() === 'data'\n ? { display: 'none' }\n : isExpanded()\n ? { height: '100%', display: 'block' }\n : { height: params().height || '250px', display: 'block' }\n }\n >\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={title()}\n aria-describedby={descriptionId}\n aria-hidden={activeView() !== 'chart' || Boolean(error())}\n />\n <Show when={isLoading() && activeView() === 'chart'}>\n <div class=\"absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80\">\n <div class=\"flex flex-col items-center gap-2\">\n <div class=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\" />\n <span class=\"text-sm text-gray-500 dark:text-gray-400\">Loading chart...</span>\n </div>\n </div>\n </Show>\n </div>\n </div>\n )}\n />\n </ExpandableWrapper>\n );\n};\n"],"names":["ChartJS","chartJSLoadPromise","loadChartJS","then","module","default","Chart","catch","err","isChartJSAvailable","ContextAwareChartLayout","props","render","useExpanded","ChartJSRenderer","isLoading","setIsLoading","createSignal","error","setError","activeView","setActiveView","canvasRef","chartInstance","renderVersion","params","component","tableData","createMemo","chartToDataTable","telemetry","useTelemetry","strings","useMCPUIStrings","descriptionId","createUniqueId","title","chartView","exportEnabled","exportable","copyDataJSON","JSON","stringify","type","data","handleExportPNG","url","toDataURL","a","document","createElement","href","download","replace","toLowerCase","click","createEffect","chartParams","version","undefined","destroy","baseOptions","responsive","maintainAspectRatio","options","plugins","legend","display","position","timeAxis","ta","scales","x","time","parser","unit","tooltipFormat","min","max","Error","message","dispatch","errorMessage","id","componentType","ts","Date","now","onError","queueMicrotask","resize","onCleanup","_$createComponent","ExpandableWrapper","copyData","copyLabel","toolbarVariant","children","isExpanded","_el$","_$getNextElement","_tmpl$6","_el$2","firstChild","_el$3","_el$5","nextSibling","_el$6","_el$7","_el$8","_el$0","_el$1","_co$","_$getNextMarker","_el$10","_el$12","_el$13","_co$2","_el$11","_el$14","_el$15","_co$3","_el$38","_el$39","_co$9","_el$40","_el$41","_co$0","_el$33","_el$34","_el$36","_el$37","_co$8","_$insert","Show","when","_el$4","_tmpl$","$$click","chartDataView","_el$9","_tmpl$2","_$effect","_$setProperty","Boolean","_$runHydrationEvents","_$setAttribute","chartDataSummary","_$memo","DegradedFallback","_$mergeProps","caption","_el$16","_tmpl$4","_el$17","_el$18","_el$20","_el$21","_co$4","_el$19","_el$22","_el$23","_co$5","_el$24","_el$25","_el$26","_el$29","_el$30","_co$6","_el$31","_el$32","_co$7","chartDataTable","For","each","columns","column","_el$42","_tmpl$7","rows","row","_el$43","_tmpl$8","_column","index","_el$44","_tmpl$9","String","length","_el$27","_tmpl$3","_el$28","chartNoData","Math","_p$","_v$","_v$2","height","e","_$className","t","_$style","_ref$","_$use","_tmpl$5","_v$3","className","_v$4","chartViewSelector","_v$5","_v$6","_v$7","_v$8","_v$9","_v$0","_v$1","_v$10","o","i","n","s","h","r","d","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentToolbar.cjs","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For,
|
|
1
|
+
{"version":3,"file":"ComponentToolbar.cjs","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: 'M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z',\n check: 'M5 13l4 4L19 7',\n download: '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',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-green-500'\n if (isActive()) return 'text-blue-500 dark:text-blue-400'\n return 'text-gray-500 dark:text-gray-400'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 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`}\n title={props.action.label}\n aria-label={props.action.label}\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","e","_$setAttribute","t","a","o","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,IAAAA,eAAAC,MAAA;AAAAC,eAAAH,MAAAI,IAAAA,gBAEKC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,IAAAA,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,eAAA,MAAAC,IAAAA,UAAAZ,MAFtC,YAAYF,gBAAAA,CAAiB,oFAAoF,CAAA;AAAA,WAAAE;AAAAA,EAAA,GAAA;AAMjI;AAGA,MAAMU,gBAAuDb,CAAAA,UAAU;AACrE,QAAM,CAACgB,WAAWC,YAAY,IAAIC,QAAAA,aAAa,KAAK;AAEpD,QAAMC,cAAcA,MAAM;AACxBnB,UAAMY,OAAOQ,QAAAA;AACb,QAAIpB,MAAMY,OAAOS,cAAc;AAC7BJ,mBAAa,IAAI;AACjBK,iBAAW,MAAML,aAAa,KAAK,GAAG,GAAI;AAAA,IAC5C;AAAA,EACF;AAEA,QAAMM,WAAWA,MAAMP,UAAAA,IAAcvB,MAAME,QAAQF,MAAMO,MAAMY,OAAOY,IAAI;AAC1E,QAAMC,WAAWA,MAAMzB,MAAMY,OAAOc;AACpC,QAAMC,aAAaA,MAAM;AACvB,QAAIX,UAAAA,EAAa,QAAO;AACxB,QAAIS,SAAAA,EAAY,QAAO;AACvB,WAAO;AAAA,EACT;AAEA,UAAA,MAAA;AAAA,QAAAG,QAAAxB,mBAAAyB,OAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAEad;AAAWL,QAAAA,OAAAoB,CAAAA,QAAA;AAAA,UAAAC,MAEbnC,MAAMY,OAAOwB,OAAKC,OACbrC,MAAMY,OAAOwB,OAAKE,OAElB,WAAWX,WAAAA,CAAY,IAAEY,OACsChB,SAAAA;AAAUY,cAAAD,IAAAM,KAAAC,IAAAA,aAAAb,OAAA,SAAAM,IAAAM,IAAAL,GAAA;AAAAE,eAAAH,IAAAQ,KAAAD,IAAAA,aAAAb,OAAA,cAAAM,IAAAQ,IAAAL,IAAA;AAAAC,eAAAJ,IAAAS,KAAAF,IAAAA,aAAAX,OAAA,SAAAI,IAAAS,IAAAL,IAAA;AAAAC,eAAAL,IAAAU,KAAAH,IAAAA,aAAAT,OAAA,KAAAE,IAAAU,IAAAL,IAAA;AAAA,aAAAL;AAAAA,IAAA,GAAA;AAAA,MAAAM,GAAAK;AAAAA,MAAAH,GAAAG;AAAAA,MAAAF,GAAAE;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,2BAAAA;AAAA,WAAAlB;AAAAA,EAAA,GAAA;AAI3F;AAACmB,IAAAA,eAAA,CAAA,OAAA,CAAA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentToolbar.d.ts","sourceRoot":"","sources":["../../src/components/ComponentToolbar.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"ComponentToolbar.d.ts","sourceRoot":"","sources":["../../src/components/ComponentToolbar.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAqB,MAAM,UAAU,CAAA;AAEvD,yCAAyC;AACzC,QAAA,MAAM,KAAK;;;;;;CAMD,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,KAAK,CAAA;AAE5C,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,IAAI,EAAE,WAAW,CAAA;IACjB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,gEAAgE;IAChE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,cAAc,CAAA;CACrD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CAgB7D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentToolbar.js","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For,
|
|
1
|
+
{"version":3,"file":"ComponentToolbar.js","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: 'M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z',\n check: 'M5 13l4 4L19 7',\n download: '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',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-green-500'\n if (isActive()) return 'text-blue-500 dark:text-blue-400'\n return 'text-gray-500 dark:text-gray-400'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 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`}\n title={props.action.label}\n aria-label={props.action.label}\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","e","_$setAttribute","t","a","o","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA;AAAAC,WAAAH,MAAAI,gBAEKC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,WAAA,MAAAC,UAAAZ,MAFtC,YAAYF,gBAAAA,CAAiB,oFAAoF,CAAA;AAAA,WAAAE;AAAAA,EAAA,GAAA;AAMjI;AAGA,MAAMU,gBAAuDb,CAAAA,UAAU;AACrE,QAAM,CAACgB,WAAWC,YAAY,IAAIC,aAAa,KAAK;AAEpD,QAAMC,cAAcA,MAAM;AACxBnB,UAAMY,OAAOQ,QAAAA;AACb,QAAIpB,MAAMY,OAAOS,cAAc;AAC7BJ,mBAAa,IAAI;AACjBK,iBAAW,MAAML,aAAa,KAAK,GAAG,GAAI;AAAA,IAC5C;AAAA,EACF;AAEA,QAAMM,WAAWA,MAAMP,UAAAA,IAAcvB,MAAME,QAAQF,MAAMO,MAAMY,OAAOY,IAAI;AAC1E,QAAMC,WAAWA,MAAMzB,MAAMY,OAAOc;AACpC,QAAMC,aAAaA,MAAM;AACvB,QAAIX,UAAAA,EAAa,QAAO;AACxB,QAAIS,SAAAA,EAAY,QAAO;AACvB,WAAO;AAAA,EACT;AAEA,UAAA,MAAA;AAAA,QAAAG,QAAAxB,eAAAyB,OAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAEad;AAAWL,WAAAoB,CAAAA,QAAA;AAAA,UAAAC,MAEbnC,MAAMY,OAAOwB,OAAKC,OACbrC,MAAMY,OAAOwB,OAAKE,OAElB,WAAWX,WAAAA,CAAY,IAAEY,OACsChB,SAAAA;AAAUY,cAAAD,IAAAM,KAAAC,aAAAb,OAAA,SAAAM,IAAAM,IAAAL,GAAA;AAAAE,eAAAH,IAAAQ,KAAAD,aAAAb,OAAA,cAAAM,IAAAQ,IAAAL,IAAA;AAAAC,eAAAJ,IAAAS,KAAAF,aAAAX,OAAA,SAAAI,IAAAS,IAAAL,IAAA;AAAAC,eAAAL,IAAAU,KAAAH,aAAAT,OAAA,KAAAE,IAAAU,IAAAL,IAAA;AAAA,aAAAL;AAAAA,IAAA,GAAA;AAAA,MAAAM,GAAAK;AAAAA,MAAAH,GAAAG;AAAAA,MAAAF,GAAAE;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAAlB;AAAAA,EAAA,GAAA;AAI3F;AAACmB,eAAA,CAAA,OAAA,CAAA;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const web = require("solid-js/web");
|
|
4
|
+
const solidJs = require("solid-js");
|
|
5
|
+
const EditableLayoutContext = solidJs.createContext(false);
|
|
6
|
+
const EditableLayoutProvider = (props) => web.createComponent(EditableLayoutContext.Provider, {
|
|
7
|
+
value: true,
|
|
8
|
+
get children() {
|
|
9
|
+
return props.children;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
function useEditableLayoutPositions() {
|
|
13
|
+
return solidJs.useContext(EditableLayoutContext);
|
|
14
|
+
}
|
|
15
|
+
exports.EditableLayoutProvider = EditableLayoutProvider;
|
|
16
|
+
exports.useEditableLayoutPositions = useEditableLayoutPositions;
|
|
17
|
+
//# sourceMappingURL=EditableLayoutContext.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableLayoutContext.cjs","sources":["../../src/components/EditableLayoutContext.tsx"],"sourcesContent":["/** Private context: editor canvases must keep authored grid positions. */\nimport { createContext, useContext, type ParentComponent } from 'solid-js'\n\nconst EditableLayoutContext = createContext(false)\n\nexport const EditableLayoutProvider: ParentComponent = (props) => (\n <EditableLayoutContext.Provider value={true}>{props.children}</EditableLayoutContext.Provider>\n)\n\nexport function useEditableLayoutPositions(): boolean {\n return useContext(EditableLayoutContext)\n}\n"],"names":["EditableLayoutContext","createContext","EditableLayoutProvider","props","_$createComponent","Provider","value","children","useEditableLayoutPositions","useContext"],"mappings":";;;;AAGA,MAAMA,wBAAwBC,QAAAA,cAAc,KAAK;AAE1C,MAAMC,yBAA2CC,CAAAA,UAAKC,oBAC1DJ,sBAAsBK,UAAQ;AAAA,EAACC,OAAO;AAAA,EAAI,IAAAC,WAAA;AAAA,WAAGJ,MAAMI;AAAAA,EAAQ;AAAA,CAAA;AAGvD,SAASC,6BAAsC;AACpD,SAAOC,QAAAA,WAAWT,qBAAqB;AACzC;;;"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Private context: editor canvases must keep authored grid positions. */
|
|
2
|
+
import { type ParentComponent } from 'solid-js';
|
|
3
|
+
export declare const EditableLayoutProvider: ParentComponent;
|
|
4
|
+
export declare function useEditableLayoutPositions(): boolean;
|
|
5
|
+
//# sourceMappingURL=EditableLayoutContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableLayoutContext.d.ts","sourceRoot":"","sources":["../../src/components/EditableLayoutContext.tsx"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAI1E,eAAO,MAAM,sBAAsB,EAAE,eAEpC,CAAA;AAED,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createComponent } from "solid-js/web";
|
|
2
|
+
import { createContext, useContext } from "solid-js";
|
|
3
|
+
const EditableLayoutContext = createContext(false);
|
|
4
|
+
const EditableLayoutProvider = (props) => createComponent(EditableLayoutContext.Provider, {
|
|
5
|
+
value: true,
|
|
6
|
+
get children() {
|
|
7
|
+
return props.children;
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
function useEditableLayoutPositions() {
|
|
11
|
+
return useContext(EditableLayoutContext);
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
EditableLayoutProvider,
|
|
15
|
+
useEditableLayoutPositions
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=EditableLayoutContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableLayoutContext.js","sources":["../../src/components/EditableLayoutContext.tsx"],"sourcesContent":["/** Private context: editor canvases must keep authored grid positions. */\nimport { createContext, useContext, type ParentComponent } from 'solid-js'\n\nconst EditableLayoutContext = createContext(false)\n\nexport const EditableLayoutProvider: ParentComponent = (props) => (\n <EditableLayoutContext.Provider value={true}>{props.children}</EditableLayoutContext.Provider>\n)\n\nexport function useEditableLayoutPositions(): boolean {\n return useContext(EditableLayoutContext)\n}\n"],"names":["EditableLayoutContext","createContext","EditableLayoutProvider","props","_$createComponent","Provider","value","children","useEditableLayoutPositions","useContext"],"mappings":";;AAGA,MAAMA,wBAAwBC,cAAc,KAAK;AAE1C,MAAMC,yBAA2CC,CAAAA,UAAKC,gBAC1DJ,sBAAsBK,UAAQ;AAAA,EAACC,OAAO;AAAA,EAAI,IAAAC,WAAA;AAAA,WAAGJ,MAAMI;AAAAA,EAAQ;AAAA,CAAA;AAGvD,SAASC,6BAAsC;AACpD,SAAOC,WAAWT,qBAAqB;AACzC;"}
|