@leanmcp/ui 0.1.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/dist/index.mjs ADDED
@@ -0,0 +1,762 @@
1
+ import 'reflect-metadata';
2
+ import React7, { forwardRef, useState, useEffect, useCallback, createContext, useContext, useMemo, useRef } from 'react';
3
+ import { PostMessageTransport, App } from '@modelcontextprotocol/ext-apps';
4
+ import { Slot } from '@radix-ui/react-slot';
5
+ import { clsx } from 'clsx';
6
+ import { useReactTable, getFilteredRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
7
+ import { Chart as Chart$1, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend } from 'chart.js';
8
+ import { Chart as Chart$2 } from 'react-chartjs-2';
9
+ import { Highlight, themes } from 'prism-react-renderer';
10
+
11
+ var __defProp = Object.defineProperty;
12
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
13
+ var UI_APP_COMPONENT_KEY = "ui:app:component";
14
+ var UI_APP_URI_KEY = "ui:app:uri";
15
+ var UI_APP_OPTIONS_KEY = "ui:app:options";
16
+ function UIApp(options) {
17
+ return (target, propertyKey, descriptor) => {
18
+ const methodName = String(propertyKey);
19
+ const className = target.constructor.name.toLowerCase().replace("service", "");
20
+ const uri = options.uri ?? `ui://${className}/${methodName}`;
21
+ Reflect.defineMetadata(UI_APP_COMPONENT_KEY, options.component, descriptor.value);
22
+ Reflect.defineMetadata(UI_APP_URI_KEY, uri, descriptor.value);
23
+ Reflect.defineMetadata(UI_APP_OPTIONS_KEY, options, descriptor.value);
24
+ const existingMeta = Reflect.getMetadata("tool:meta", descriptor.value) || {};
25
+ Reflect.defineMetadata("tool:meta", {
26
+ ...existingMeta,
27
+ "ui/resourceUri": uri
28
+ }, descriptor.value);
29
+ return descriptor;
30
+ };
31
+ }
32
+ __name(UIApp, "UIApp");
33
+ function getUIAppMetadata(target) {
34
+ const component = Reflect.getMetadata(UI_APP_COMPONENT_KEY, target);
35
+ if (!component) return void 0;
36
+ return {
37
+ component,
38
+ uri: Reflect.getMetadata(UI_APP_URI_KEY, target),
39
+ ...Reflect.getMetadata(UI_APP_OPTIONS_KEY, target)
40
+ };
41
+ }
42
+ __name(getUIAppMetadata, "getUIAppMetadata");
43
+ function getUIAppUri(target) {
44
+ return Reflect.getMetadata(UI_APP_URI_KEY, target);
45
+ }
46
+ __name(getUIAppUri, "getUIAppUri");
47
+ var McpAppContext = /* @__PURE__ */ createContext(null);
48
+ function AppProvider({ appInfo, capabilities = {}, options = {
49
+ autoResize: true
50
+ }, children }) {
51
+ const [app, setApp] = useState(null);
52
+ const [isConnected, setIsConnected] = useState(false);
53
+ const [error, setError] = useState(null);
54
+ const [hostContext, setHostContext] = useState({});
55
+ const [toolInput, setToolInput] = useState(null);
56
+ const [toolInputPartial, setToolInputPartial] = useState(null);
57
+ const [toolResult, setToolResult] = useState(null);
58
+ useEffect(() => {
59
+ let mounted = true;
60
+ let appInstance = null;
61
+ async function connect() {
62
+ try {
63
+ const transport = new PostMessageTransport(window.parent);
64
+ appInstance = new App(appInfo, capabilities, options);
65
+ appInstance.ontoolinput = (params) => {
66
+ if (mounted) {
67
+ setToolInput(params.arguments);
68
+ }
69
+ };
70
+ appInstance.ontoolinputpartial = (params) => {
71
+ if (mounted) {
72
+ setToolInputPartial(params.arguments);
73
+ }
74
+ };
75
+ appInstance.ontoolresult = (params) => {
76
+ if (mounted) {
77
+ setToolResult(params);
78
+ }
79
+ };
80
+ appInstance.onhostcontextchanged = (params) => {
81
+ if (mounted) {
82
+ setHostContext((prev) => ({
83
+ ...prev,
84
+ ...params
85
+ }));
86
+ }
87
+ };
88
+ await appInstance.connect(transport);
89
+ if (mounted) {
90
+ setApp(appInstance);
91
+ setIsConnected(true);
92
+ setError(null);
93
+ }
94
+ } catch (err) {
95
+ if (mounted) {
96
+ setError(err instanceof Error ? err : new Error(String(err)));
97
+ setIsConnected(false);
98
+ }
99
+ }
100
+ }
101
+ __name(connect, "connect");
102
+ connect();
103
+ return () => {
104
+ mounted = false;
105
+ if (appInstance) {
106
+ appInstance.close();
107
+ }
108
+ };
109
+ }, [
110
+ appInfo.name,
111
+ appInfo.version
112
+ ]);
113
+ const callTool = useCallback(async (name, args = {}) => {
114
+ if (!app) {
115
+ throw new Error("Not connected to host");
116
+ }
117
+ const result = await app.callServerTool({
118
+ name,
119
+ arguments: args
120
+ });
121
+ setToolResult(result);
122
+ return result;
123
+ }, [
124
+ app
125
+ ]);
126
+ const sendMessage = useCallback(async (text) => {
127
+ if (!app) {
128
+ console.warn("[AppProvider] Not connected - cannot send message");
129
+ return;
130
+ }
131
+ await app.sendMessage({
132
+ role: "user",
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text
137
+ }
138
+ ]
139
+ });
140
+ }, [
141
+ app
142
+ ]);
143
+ const sendLog = useCallback(async (level, data) => {
144
+ if (!app) {
145
+ console.log(`[MCP App] ${level}:`, data);
146
+ return;
147
+ }
148
+ await app.sendLog({
149
+ level,
150
+ data
151
+ });
152
+ }, [
153
+ app
154
+ ]);
155
+ const openLink = useCallback(async (url) => {
156
+ if (!app) {
157
+ window.open(url, "_blank", "noopener,noreferrer");
158
+ return;
159
+ }
160
+ await app.sendOpenLink({
161
+ url
162
+ });
163
+ }, [
164
+ app
165
+ ]);
166
+ const value = {
167
+ app,
168
+ isConnected,
169
+ error,
170
+ hostContext,
171
+ toolInput,
172
+ toolInputPartial,
173
+ toolResult,
174
+ callTool,
175
+ sendMessage,
176
+ sendLog,
177
+ openLink
178
+ };
179
+ const theme = hostContext.theme ?? "light";
180
+ return /* @__PURE__ */ React7.createElement(McpAppContext.Provider, {
181
+ value
182
+ }, /* @__PURE__ */ React7.createElement("div", {
183
+ className: "lui-root",
184
+ "data-theme": theme
185
+ }, children));
186
+ }
187
+ __name(AppProvider, "AppProvider");
188
+ var ssrDefaultContext = {
189
+ app: null,
190
+ isConnected: false,
191
+ error: null,
192
+ hostContext: {},
193
+ toolInput: null,
194
+ toolInputPartial: null,
195
+ toolResult: null,
196
+ callTool: /* @__PURE__ */ __name(async () => {
197
+ throw new Error("callTool not available during SSR");
198
+ }, "callTool"),
199
+ sendMessage: /* @__PURE__ */ __name(async () => {
200
+ console.warn("sendMessage not available during SSR");
201
+ }, "sendMessage"),
202
+ sendLog: /* @__PURE__ */ __name(async () => {
203
+ console.warn("sendLog not available during SSR");
204
+ }, "sendLog"),
205
+ openLink: /* @__PURE__ */ __name(async () => {
206
+ console.warn("openLink not available during SSR");
207
+ }, "openLink")
208
+ };
209
+ function useMcpApp() {
210
+ const context = useContext(McpAppContext);
211
+ if (!context) {
212
+ return ssrDefaultContext;
213
+ }
214
+ return context;
215
+ }
216
+ __name(useMcpApp, "useMcpApp");
217
+ function useTool(toolName) {
218
+ const { callTool } = useMcpApp();
219
+ const [loading, setLoading] = useState(false);
220
+ const [result, setResult] = useState(null);
221
+ const [error, setError] = useState(null);
222
+ const call = useCallback(async (args = {}) => {
223
+ setLoading(true);
224
+ setError(null);
225
+ try {
226
+ const response = await callTool(toolName, args);
227
+ const data = response?.structuredContent ?? response;
228
+ setResult(data);
229
+ return data;
230
+ } catch (err) {
231
+ const error2 = err instanceof Error ? err : new Error(String(err));
232
+ setError(error2);
233
+ throw error2;
234
+ } finally {
235
+ setLoading(false);
236
+ }
237
+ }, [
238
+ callTool,
239
+ toolName
240
+ ]);
241
+ const reset = useCallback(() => {
242
+ setResult(null);
243
+ setError(null);
244
+ }, []);
245
+ return {
246
+ call,
247
+ loading,
248
+ result,
249
+ error,
250
+ reset
251
+ };
252
+ }
253
+ __name(useTool, "useTool");
254
+
255
+ // src/mcp/useToolResult.ts
256
+ function useToolResult() {
257
+ const { toolResult } = useMcpApp();
258
+ let result = null;
259
+ let textContent = null;
260
+ if (toolResult) {
261
+ if ("structuredContent" in toolResult && toolResult.structuredContent) {
262
+ result = toolResult.structuredContent;
263
+ }
264
+ if (!result && toolResult.content) {
265
+ const textItem = toolResult.content.find((c) => c.type === "text");
266
+ if (textItem) {
267
+ textContent = textItem.text;
268
+ try {
269
+ result = JSON.parse(textItem.text);
270
+ } catch {
271
+ }
272
+ }
273
+ }
274
+ }
275
+ return {
276
+ result,
277
+ rawResult: toolResult,
278
+ hasResult: toolResult !== null,
279
+ textContent
280
+ };
281
+ }
282
+ __name(useToolResult, "useToolResult");
283
+
284
+ // src/mcp/useToolInput.ts
285
+ function useToolInput() {
286
+ const { toolInput } = useMcpApp();
287
+ return {
288
+ input: toolInput,
289
+ hasInput: toolInput !== null
290
+ };
291
+ }
292
+ __name(useToolInput, "useToolInput");
293
+
294
+ // src/mcp/useToolInputPartial.ts
295
+ function useToolInputPartial() {
296
+ const { toolInputPartial } = useMcpApp();
297
+ return {
298
+ partialArgs: toolInputPartial,
299
+ isStreaming: toolInputPartial !== null
300
+ };
301
+ }
302
+ __name(useToolInputPartial, "useToolInputPartial");
303
+
304
+ // src/mcp/useHostContext.ts
305
+ function useHostContext() {
306
+ const { hostContext } = useMcpApp();
307
+ return {
308
+ theme: hostContext.theme ?? "light",
309
+ displayMode: hostContext.displayMode ?? "inline",
310
+ viewport: hostContext.viewport ?? null,
311
+ locale: hostContext.locale ?? null,
312
+ timeZone: hostContext.timeZone ?? null,
313
+ platform: hostContext.platform ?? null,
314
+ rawContext: hostContext
315
+ };
316
+ }
317
+ __name(useHostContext, "useHostContext");
318
+ var Button = /* @__PURE__ */ forwardRef(({ className, variant = "primary", size = "md", loading = false, disabled, asChild = false, leftIcon, rightIcon, children, ...props }, ref) => {
319
+ const Comp = asChild ? Slot : "button";
320
+ return /* @__PURE__ */ React7.createElement(Comp, {
321
+ ref,
322
+ className: clsx("lui-button", `lui-button--${variant}`, `lui-button--${size}`, loading && "lui-button--loading", className),
323
+ disabled: disabled || loading,
324
+ ...props
325
+ }, loading && /* @__PURE__ */ React7.createElement("span", {
326
+ className: "lui-button__spinner",
327
+ "aria-hidden": "true"
328
+ }, /* @__PURE__ */ React7.createElement("svg", {
329
+ viewBox: "0 0 24 24",
330
+ fill: "none",
331
+ className: "lui-spinner-icon"
332
+ }, /* @__PURE__ */ React7.createElement("circle", {
333
+ cx: "12",
334
+ cy: "12",
335
+ r: "10",
336
+ stroke: "currentColor",
337
+ strokeWidth: "3",
338
+ strokeLinecap: "round",
339
+ strokeDasharray: "32",
340
+ strokeDashoffset: "12"
341
+ }))), leftIcon && !loading && /* @__PURE__ */ React7.createElement("span", {
342
+ className: "lui-button__icon"
343
+ }, leftIcon), /* @__PURE__ */ React7.createElement("span", {
344
+ className: "lui-button__content"
345
+ }, children), rightIcon && /* @__PURE__ */ React7.createElement("span", {
346
+ className: "lui-button__icon"
347
+ }, rightIcon));
348
+ });
349
+ Button.displayName = "Button";
350
+
351
+ // src/mcp/ActionButton.tsx
352
+ function ActionButton({ toolName, toolArgs = {}, onToolSuccess, onToolError, showResult = false, renderResult, children, ...buttonProps }) {
353
+ const { call, loading, result, error } = useTool(toolName);
354
+ const [hasResult, setHasResult] = useState(false);
355
+ const handleClick = /* @__PURE__ */ __name(async () => {
356
+ try {
357
+ const res = await call(toolArgs);
358
+ setHasResult(true);
359
+ onToolSuccess?.(res);
360
+ } catch (err) {
361
+ onToolError?.(err instanceof Error ? err : new Error(String(err)));
362
+ }
363
+ }, "handleClick");
364
+ return /* @__PURE__ */ React7.createElement("div", {
365
+ className: "lui-action-button-wrapper"
366
+ }, /* @__PURE__ */ React7.createElement(Button, {
367
+ ...buttonProps,
368
+ loading,
369
+ onClick: handleClick
370
+ }, children), showResult && hasResult && result !== null && /* @__PURE__ */ React7.createElement("div", {
371
+ className: "lui-action-button-result"
372
+ }, renderResult ? renderResult(result) : /* @__PURE__ */ React7.createElement("pre", null, JSON.stringify(result, null, 2))), error && /* @__PURE__ */ React7.createElement("div", {
373
+ className: "lui-action-button-error"
374
+ }, error.message));
375
+ }
376
+ __name(ActionButton, "ActionButton");
377
+ var Input = /* @__PURE__ */ forwardRef(({ className, label, helperText, error, size = "md", leftElement, rightElement, fullWidth = false, id, ...props }, ref) => {
378
+ const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
379
+ const hasError = Boolean(error);
380
+ return /* @__PURE__ */ React7.createElement("div", {
381
+ className: clsx("lui-input-wrapper", fullWidth && "lui-input-wrapper--full-width", className)
382
+ }, label && /* @__PURE__ */ React7.createElement("label", {
383
+ htmlFor: inputId,
384
+ className: "lui-input-label"
385
+ }, label), /* @__PURE__ */ React7.createElement("div", {
386
+ className: clsx("lui-input-container", `lui-input-container--${size}`, hasError && "lui-input-container--error", leftElement && "lui-input-container--has-left", rightElement && "lui-input-container--has-right")
387
+ }, leftElement && /* @__PURE__ */ React7.createElement("span", {
388
+ className: "lui-input-element lui-input-element--left"
389
+ }, leftElement), /* @__PURE__ */ React7.createElement("input", {
390
+ ref,
391
+ id: inputId,
392
+ className: "lui-input",
393
+ "aria-invalid": hasError,
394
+ "aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
395
+ ...props
396
+ }), rightElement && /* @__PURE__ */ React7.createElement("span", {
397
+ className: "lui-input-element lui-input-element--right"
398
+ }, rightElement)), (error || helperText) && /* @__PURE__ */ React7.createElement("p", {
399
+ id: error ? `${inputId}-error` : `${inputId}-helper`,
400
+ className: clsx("lui-input-message", error && "lui-input-message--error")
401
+ }, error || helperText));
402
+ });
403
+ Input.displayName = "Input";
404
+ function ToolForm({ toolName, fields, submitText = "Submit", onSuccess, onError, showResult = false, className }) {
405
+ const { call, loading, result, error } = useTool(toolName);
406
+ const [formData, setFormData] = useState(() => {
407
+ const initial = {};
408
+ fields.forEach((field) => {
409
+ if (field.defaultValue !== void 0) {
410
+ initial[field.name] = field.defaultValue;
411
+ }
412
+ });
413
+ return initial;
414
+ });
415
+ const handleSubmit = /* @__PURE__ */ __name(async (e) => {
416
+ e.preventDefault();
417
+ const args = {};
418
+ fields.forEach((field) => {
419
+ const value = formData[field.name];
420
+ if (field.type === "number" && value !== void 0) {
421
+ args[field.name] = Number(value);
422
+ } else {
423
+ args[field.name] = value;
424
+ }
425
+ });
426
+ try {
427
+ const res = await call(args);
428
+ onSuccess?.(res);
429
+ } catch (err) {
430
+ onError?.(err instanceof Error ? err : new Error(String(err)));
431
+ }
432
+ }, "handleSubmit");
433
+ const handleChange = /* @__PURE__ */ __name((name, value) => {
434
+ setFormData((prev) => ({
435
+ ...prev,
436
+ [name]: value
437
+ }));
438
+ }, "handleChange");
439
+ return /* @__PURE__ */ React7.createElement("form", {
440
+ className: clsx("lui-tool-form", className),
441
+ onSubmit: handleSubmit
442
+ }, /* @__PURE__ */ React7.createElement("div", {
443
+ className: "lui-tool-form-fields"
444
+ }, fields.map((field) => /* @__PURE__ */ React7.createElement("div", {
445
+ key: field.name,
446
+ className: "lui-tool-form-field"
447
+ }, field.type === "textarea" ? /* @__PURE__ */ React7.createElement("div", {
448
+ className: "lui-input-wrapper lui-input-wrapper--full-width"
449
+ }, /* @__PURE__ */ React7.createElement("label", {
450
+ className: "lui-input-label"
451
+ }, field.label), /* @__PURE__ */ React7.createElement("textarea", {
452
+ className: "lui-tool-form-textarea",
453
+ name: field.name,
454
+ placeholder: field.placeholder,
455
+ required: field.required,
456
+ value: formData[field.name] ?? "",
457
+ onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange")
458
+ }), field.helperText && /* @__PURE__ */ React7.createElement("p", {
459
+ className: "lui-input-message"
460
+ }, field.helperText)) : /* @__PURE__ */ React7.createElement(Input, {
461
+ fullWidth: true,
462
+ label: field.label,
463
+ type: field.type ?? "text",
464
+ name: field.name,
465
+ placeholder: field.placeholder,
466
+ required: field.required,
467
+ helperText: field.helperText,
468
+ value: formData[field.name] ?? "",
469
+ onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange")
470
+ })))), /* @__PURE__ */ React7.createElement("div", {
471
+ className: "lui-tool-form-actions"
472
+ }, /* @__PURE__ */ React7.createElement(Button, {
473
+ type: "submit",
474
+ loading
475
+ }, submitText)), error && /* @__PURE__ */ React7.createElement("div", {
476
+ className: "lui-tool-form-error"
477
+ }, error.message), showResult && result !== null && /* @__PURE__ */ React7.createElement("div", {
478
+ className: "lui-tool-form-result"
479
+ }, /* @__PURE__ */ React7.createElement("pre", null, JSON.stringify(result, null, 2))));
480
+ }
481
+ __name(ToolForm, "ToolForm");
482
+ var Card = /* @__PURE__ */ forwardRef(({ className, variant = "default", padding = "md", interactive = false, children, ...props }, ref) => {
483
+ return /* @__PURE__ */ React7.createElement("div", {
484
+ ref,
485
+ className: clsx("lui-card", `lui-card--${variant}`, `lui-card--padding-${padding}`, interactive && "lui-card--interactive", className),
486
+ ...props
487
+ }, children);
488
+ });
489
+ Card.displayName = "Card";
490
+ var CardHeader = /* @__PURE__ */ forwardRef(({ className, title, description, action, children, ...props }, ref) => {
491
+ return /* @__PURE__ */ React7.createElement("div", {
492
+ ref,
493
+ className: clsx("lui-card-header", className),
494
+ ...props
495
+ }, (title || description) && /* @__PURE__ */ React7.createElement("div", {
496
+ className: "lui-card-header__text"
497
+ }, title && /* @__PURE__ */ React7.createElement("h3", {
498
+ className: "lui-card-header__title"
499
+ }, title), description && /* @__PURE__ */ React7.createElement("p", {
500
+ className: "lui-card-header__description"
501
+ }, description)), action && /* @__PURE__ */ React7.createElement("div", {
502
+ className: "lui-card-header__action"
503
+ }, action), children);
504
+ });
505
+ CardHeader.displayName = "CardHeader";
506
+ var CardContent = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
507
+ return /* @__PURE__ */ React7.createElement("div", {
508
+ ref,
509
+ className: clsx("lui-card-content", className),
510
+ ...props
511
+ }, children);
512
+ });
513
+ CardContent.displayName = "CardContent";
514
+ var CardFooter = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
515
+ return /* @__PURE__ */ React7.createElement("div", {
516
+ ref,
517
+ className: clsx("lui-card-footer", className),
518
+ ...props
519
+ }, children);
520
+ });
521
+ CardFooter.displayName = "CardFooter";
522
+ function DataGrid({ data, columns, searchable = false, searchPlaceholder = "Search...", onRowClick, loading = false, emptyMessage = "No data", className }) {
523
+ const [sorting, setSorting] = useState([]);
524
+ const [globalFilter, setGlobalFilter] = useState("");
525
+ const tableColumns = useMemo(() => columns.map((col) => ({
526
+ id: String(col.key),
527
+ accessorKey: col.key,
528
+ header: col.header,
529
+ cell: col.cell ? ({ getValue, row }) => col.cell(getValue(), row.original) : ({ getValue }) => String(getValue() ?? ""),
530
+ enableSorting: col.sortable ?? true,
531
+ size: typeof col.width === "number" ? col.width : void 0
532
+ })), [
533
+ columns
534
+ ]);
535
+ const table = useReactTable({
536
+ data,
537
+ columns: tableColumns,
538
+ state: {
539
+ sorting,
540
+ globalFilter
541
+ },
542
+ onSortingChange: setSorting,
543
+ onGlobalFilterChange: setGlobalFilter,
544
+ getCoreRowModel: getCoreRowModel(),
545
+ getSortedRowModel: getSortedRowModel(),
546
+ getFilteredRowModel: getFilteredRowModel()
547
+ });
548
+ return /* @__PURE__ */ React7.createElement("div", {
549
+ className: clsx("lui-datagrid", className)
550
+ }, searchable && /* @__PURE__ */ React7.createElement("div", {
551
+ className: "lui-datagrid-search"
552
+ }, /* @__PURE__ */ React7.createElement("input", {
553
+ type: "text",
554
+ value: globalFilter,
555
+ onChange: /* @__PURE__ */ __name((e) => setGlobalFilter(e.target.value), "onChange"),
556
+ placeholder: searchPlaceholder,
557
+ className: "lui-datagrid-search-input"
558
+ })), /* @__PURE__ */ React7.createElement("div", {
559
+ className: "lui-datagrid-container"
560
+ }, /* @__PURE__ */ React7.createElement("table", {
561
+ className: "lui-datagrid-table"
562
+ }, /* @__PURE__ */ React7.createElement("thead", null, table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ React7.createElement("tr", {
563
+ key: headerGroup.id
564
+ }, headerGroup.headers.map((header) => /* @__PURE__ */ React7.createElement("th", {
565
+ key: header.id,
566
+ className: clsx("lui-datagrid-th", header.column.getCanSort() && "lui-datagrid-th--sortable"),
567
+ onClick: header.column.getToggleSortingHandler(),
568
+ style: {
569
+ width: header.column.getSize()
570
+ }
571
+ }, /* @__PURE__ */ React7.createElement("div", {
572
+ className: "lui-datagrid-th-content"
573
+ }, flexRender(header.column.columnDef.header, header.getContext()), header.column.getIsSorted() && /* @__PURE__ */ React7.createElement("span", {
574
+ className: "lui-datagrid-sort-icon"
575
+ }, header.column.getIsSorted() === "asc" ? "\u2191" : "\u2193"))))))), /* @__PURE__ */ React7.createElement("tbody", null, loading ? /* @__PURE__ */ React7.createElement("tr", null, /* @__PURE__ */ React7.createElement("td", {
576
+ colSpan: columns.length,
577
+ className: "lui-datagrid-loading"
578
+ }, "Loading...")) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ React7.createElement("tr", null, /* @__PURE__ */ React7.createElement("td", {
579
+ colSpan: columns.length,
580
+ className: "lui-datagrid-empty"
581
+ }, emptyMessage)) : table.getRowModel().rows.map((row) => /* @__PURE__ */ React7.createElement("tr", {
582
+ key: row.id,
583
+ className: clsx("lui-datagrid-row", onRowClick && "lui-datagrid-row--clickable"),
584
+ onClick: /* @__PURE__ */ __name(() => onRowClick?.(row.original), "onClick")
585
+ }, row.getVisibleCells().map((cell) => /* @__PURE__ */ React7.createElement("td", {
586
+ key: cell.id,
587
+ className: "lui-datagrid-td"
588
+ }, flexRender(cell.column.columnDef.cell, cell.getContext())))))))));
589
+ }
590
+ __name(DataGrid, "DataGrid");
591
+ Chart$1.register(CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend);
592
+ function Chart({ type, data, options, height = 300, width = "100%", className }) {
593
+ const defaultOptions = {
594
+ responsive: true,
595
+ maintainAspectRatio: false,
596
+ plugins: {
597
+ legend: {
598
+ display: true,
599
+ position: "top",
600
+ labels: {
601
+ usePointStyle: true,
602
+ padding: 16
603
+ }
604
+ },
605
+ tooltip: {
606
+ mode: "index",
607
+ intersect: false,
608
+ backgroundColor: "rgba(15, 23, 42, 0.9)",
609
+ titleColor: "#f1f5f9",
610
+ bodyColor: "#cbd5e1",
611
+ borderColor: "#334155",
612
+ borderWidth: 1,
613
+ cornerRadius: 8,
614
+ padding: 12
615
+ }
616
+ },
617
+ scales: type !== "pie" && type !== "doughnut" ? {
618
+ x: {
619
+ grid: {
620
+ color: "rgba(226, 232, 240, 0.5)"
621
+ },
622
+ ticks: {
623
+ color: "#64748b"
624
+ }
625
+ },
626
+ y: {
627
+ grid: {
628
+ color: "rgba(226, 232, 240, 0.5)"
629
+ },
630
+ ticks: {
631
+ color: "#64748b"
632
+ }
633
+ }
634
+ } : void 0
635
+ };
636
+ const mergedOptions = {
637
+ ...defaultOptions,
638
+ ...options,
639
+ plugins: {
640
+ ...defaultOptions.plugins,
641
+ ...options?.plugins
642
+ }
643
+ };
644
+ return /* @__PURE__ */ React7.createElement("div", {
645
+ className: clsx("lui-chart", className),
646
+ style: {
647
+ height,
648
+ width
649
+ }
650
+ }, /* @__PURE__ */ React7.createElement(Chart$2, {
651
+ type,
652
+ data,
653
+ options: mergedOptions
654
+ }));
655
+ }
656
+ __name(Chart, "Chart");
657
+ function AppShell({ header, sidebar, footer, sidebarPosition = "left", sidebarWidth = 240, autoResize = true, padding = "md", className, children, ...props }) {
658
+ const containerRef = useRef(null);
659
+ useEffect(() => {
660
+ if (!autoResize || !containerRef.current) return;
661
+ const resizeObserver = new ResizeObserver((entries) => {
662
+ for (const entry of entries) {
663
+ const { height } = entry.contentRect;
664
+ window.parent.postMessage({
665
+ type: "resize",
666
+ height: Math.ceil(height)
667
+ }, "*");
668
+ }
669
+ });
670
+ resizeObserver.observe(containerRef.current);
671
+ return () => {
672
+ resizeObserver.disconnect();
673
+ };
674
+ }, [
675
+ autoResize
676
+ ]);
677
+ const sidebarStyle = {
678
+ width: typeof sidebarWidth === "number" ? `${sidebarWidth}px` : sidebarWidth,
679
+ flexShrink: 0
680
+ };
681
+ return /* @__PURE__ */ React7.createElement("div", {
682
+ ref: containerRef,
683
+ className: clsx("lui-app-shell", `lui-app-shell--padding-${padding}`, className),
684
+ ...props
685
+ }, header && /* @__PURE__ */ React7.createElement("header", {
686
+ className: "lui-app-shell-header"
687
+ }, header), /* @__PURE__ */ React7.createElement("div", {
688
+ className: "lui-app-shell-body"
689
+ }, sidebar && sidebarPosition === "left" && /* @__PURE__ */ React7.createElement("aside", {
690
+ className: "lui-app-shell-sidebar",
691
+ style: sidebarStyle
692
+ }, sidebar), /* @__PURE__ */ React7.createElement("main", {
693
+ className: "lui-app-shell-main"
694
+ }, children), sidebar && sidebarPosition === "right" && /* @__PURE__ */ React7.createElement("aside", {
695
+ className: "lui-app-shell-sidebar",
696
+ style: sidebarStyle
697
+ }, sidebar)), footer && /* @__PURE__ */ React7.createElement("footer", {
698
+ className: "lui-app-shell-footer"
699
+ }, footer));
700
+ }
701
+ __name(AppShell, "AppShell");
702
+ function CodeBlock({ code, language = "text", showLineNumbers = false, copyable = true, className }) {
703
+ const [copied, setCopied] = React7.useState(false);
704
+ const handleCopy = /* @__PURE__ */ __name(async () => {
705
+ await navigator.clipboard.writeText(code);
706
+ setCopied(true);
707
+ setTimeout(() => setCopied(false), 2e3);
708
+ }, "handleCopy");
709
+ return /* @__PURE__ */ React7.createElement("div", {
710
+ className: clsx("lui-code-block", className)
711
+ }, copyable && /* @__PURE__ */ React7.createElement("button", {
712
+ type: "button",
713
+ className: "lui-code-block-copy",
714
+ onClick: handleCopy,
715
+ "aria-label": copied ? "Copied!" : "Copy code"
716
+ }, copied ? /* @__PURE__ */ React7.createElement("svg", {
717
+ viewBox: "0 0 24 24",
718
+ fill: "none",
719
+ stroke: "currentColor",
720
+ strokeWidth: "2"
721
+ }, /* @__PURE__ */ React7.createElement("polyline", {
722
+ points: "20,6 9,17 4,12"
723
+ })) : /* @__PURE__ */ React7.createElement("svg", {
724
+ viewBox: "0 0 24 24",
725
+ fill: "none",
726
+ stroke: "currentColor",
727
+ strokeWidth: "2"
728
+ }, /* @__PURE__ */ React7.createElement("rect", {
729
+ x: "9",
730
+ y: "9",
731
+ width: "13",
732
+ height: "13",
733
+ rx: "2",
734
+ ry: "2"
735
+ }), /* @__PURE__ */ React7.createElement("path", {
736
+ d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
737
+ }))), /* @__PURE__ */ React7.createElement(Highlight, {
738
+ theme: themes.nightOwl,
739
+ code: code.trim(),
740
+ language
741
+ }, ({ className: hlClassName, style, tokens, getLineProps, getTokenProps }) => /* @__PURE__ */ React7.createElement("pre", {
742
+ className: clsx("lui-code-block-pre", hlClassName),
743
+ style
744
+ }, tokens.map((line, i) => /* @__PURE__ */ React7.createElement("div", {
745
+ key: i,
746
+ ...getLineProps({
747
+ line
748
+ })
749
+ }, showLineNumbers && /* @__PURE__ */ React7.createElement("span", {
750
+ className: "lui-code-block-line-number"
751
+ }, i + 1), line.map((token, key) => /* @__PURE__ */ React7.createElement("span", {
752
+ key,
753
+ ...getTokenProps({
754
+ token
755
+ })
756
+ })))))));
757
+ }
758
+ __name(CodeBlock, "CodeBlock");
759
+
760
+ export { ActionButton, AppProvider, AppShell, Button, Card, CardContent, CardFooter, CardHeader, Chart, CodeBlock, DataGrid, Input, ToolForm, UIApp, getUIAppMetadata, getUIAppUri, useHostContext, useMcpApp, useTool, useToolInput, useToolInputPartial, useToolResult };
761
+ //# sourceMappingURL=index.mjs.map
762
+ //# sourceMappingURL=index.mjs.map