@mcp-html-bridge/ui-engine 0.5.1 → 0.5.2
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/bridge.d.ts +3 -0
- package/dist/bridge.d.ts.map +1 -0
- package/{src/bridge.ts → dist/bridge.js} +6 -3
- package/dist/bridge.js.map +1 -0
- package/dist/engine.d.ts +26 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +92 -0
- package/dist/engine.js.map +1 -0
- package/dist/html-builder.d.ts +16 -0
- package/dist/html-builder.d.ts.map +1 -0
- package/dist/html-builder.js +54 -0
- package/dist/html-builder.js.map +1 -0
- package/{src/index.ts → dist/index.d.ts} +3 -26
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-renderer.d.ts +36 -0
- package/dist/llm-renderer.d.ts.map +1 -0
- package/dist/llm-renderer.js +103 -0
- package/dist/llm-renderer.js.map +1 -0
- package/dist/playground.d.ts +4 -0
- package/dist/playground.d.ts.map +1 -0
- package/{src/playground.ts → dist/playground.js} +12 -11
- package/dist/playground.js.map +1 -0
- package/dist/renderer.d.ts +7 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +345 -0
- package/dist/renderer.js.map +1 -0
- package/dist/renderers/form.d.ts +4 -0
- package/dist/renderers/form.d.ts.map +1 -0
- package/dist/renderers/form.js +181 -0
- package/dist/renderers/form.js.map +1 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.d.ts.map +1 -0
- package/{src/theme.ts → dist/theme.js} +6 -3
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities.d.ts +19 -0
- package/dist/utilities.d.ts.map +1 -0
- package/{src/utilities.ts → dist/utilities.js} +6 -3
- package/dist/utilities.js.map +1 -0
- package/package.json +4 -1
- package/src/engine.ts +0 -118
- package/src/html-builder.ts +0 -61
- package/src/llm-renderer.ts +0 -129
- package/src/renderer.ts +0 -380
- package/src/renderers/form.ts +0 -200
- package/src/types.ts +0 -60
- package/tsconfig.json +0 -8
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,wBAAgB,gBAAgB,IAAI,MAAM,CA8FzC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
// ── Bridge Protocol: postMessage/CustomEvent for bidirectional communication ──
|
|
2
|
-
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.generateBridgeJS = generateBridgeJS;
|
|
3
5
|
/** Generate inline JS for MCP bridge communication */
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
function generateBridgeJS() {
|
|
7
|
+
return `
|
|
6
8
|
// ── MCP Bridge Protocol ──
|
|
7
9
|
(function() {
|
|
8
10
|
'use strict';
|
|
@@ -96,3 +98,4 @@ export function generateBridgeJS(): string {
|
|
|
96
98
|
})();
|
|
97
99
|
`;
|
|
98
100
|
}
|
|
101
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":";AAAA,iFAAiF;;AAGjF,4CA8FC;AA/FD,sDAAsD;AACtD,SAAgB,gBAAgB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FR,CAAC;AACF,CAAC"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EngineInput, RenderOptions, JSONSchema } from './types.js';
|
|
2
|
+
import type { LLMConfig } from './llm-renderer.js';
|
|
3
|
+
/** Options for rendering */
|
|
4
|
+
interface DataRenderOptions extends RenderOptions {
|
|
5
|
+
toolName?: string;
|
|
6
|
+
toolDescription?: string;
|
|
7
|
+
/** LLM config for semantic rendering. Omit for structural fallback. */
|
|
8
|
+
llm?: LLMConfig;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Render any JSON data as a full HTML document.
|
|
12
|
+
*
|
|
13
|
+
* - If `options.llm` is provided: calls the LLM for semantic rendering (async).
|
|
14
|
+
* - If omitted: uses the structural renderer (sync, returned as resolved Promise).
|
|
15
|
+
*/
|
|
16
|
+
export declare function renderFromData(data: unknown, options?: DataRenderOptions): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Sync structural rendering (no LLM). Use when you know you don't need LLM.
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderFromDataSync(data: unknown, options?: Omit<DataRenderOptions, 'llm'>): string;
|
|
21
|
+
/** Render a form from a JSON Schema (for tool input). Always sync. */
|
|
22
|
+
export declare function renderFromSchema(schema: JSONSchema, options?: DataRenderOptions): string;
|
|
23
|
+
/** Unified API */
|
|
24
|
+
export declare function render(input: EngineInput, options?: DataRenderOptions): Promise<string>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAUnD,4BAA4B;AAC5B,UAAU,iBAAkB,SAAQ,aAAa;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAsBD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAM,GAC3C,MAAM,CAGR;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CA0BR;AAED,kBAAkB;AAClB,wBAAsB,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAajG"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderFromData = renderFromData;
|
|
4
|
+
exports.renderFromDataSync = renderFromDataSync;
|
|
5
|
+
exports.renderFromSchema = renderFromSchema;
|
|
6
|
+
exports.render = render;
|
|
7
|
+
const html_builder_js_1 = require("./html-builder.js");
|
|
8
|
+
const theme_js_1 = require("./theme.js");
|
|
9
|
+
const bridge_js_1 = require("./bridge.js");
|
|
10
|
+
const renderer_js_1 = require("./renderer.js");
|
|
11
|
+
const llm_renderer_js_1 = require("./llm-renderer.js");
|
|
12
|
+
const form_js_1 = require("./renderers/form.js");
|
|
13
|
+
const playground_js_1 = require("./playground.js");
|
|
14
|
+
const utilities_js_1 = require("./utilities.js");
|
|
15
|
+
/** Build the document wrapper around an HTML body fragment */
|
|
16
|
+
function buildDocument(body, options, extraCSS = '', extraJS = '') {
|
|
17
|
+
const cssParts = [(0, theme_js_1.generateThemeCSS)(), (0, utilities_js_1.generateUtilityCSS)(), extraCSS];
|
|
18
|
+
const jsParts = [(0, bridge_js_1.generateBridgeJS)(), extraJS];
|
|
19
|
+
if (options.debug) {
|
|
20
|
+
cssParts.push((0, playground_js_1.getPlaygroundCSS)());
|
|
21
|
+
jsParts.push((0, playground_js_1.getPlaygroundJS)());
|
|
22
|
+
}
|
|
23
|
+
const playgroundHTML = options.debug ? (0, playground_js_1.generatePlaygroundHTML)() : '';
|
|
24
|
+
return (0, html_builder_js_1.document)({
|
|
25
|
+
title: options.title ?? options.toolName ?? 'MCP Result',
|
|
26
|
+
css: cssParts.join('\n'),
|
|
27
|
+
body: body + playgroundHTML,
|
|
28
|
+
js: jsParts.join('\n'),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Render any JSON data as a full HTML document.
|
|
33
|
+
*
|
|
34
|
+
* - If `options.llm` is provided: calls the LLM for semantic rendering (async).
|
|
35
|
+
* - If omitted: uses the structural renderer (sync, returned as resolved Promise).
|
|
36
|
+
*/
|
|
37
|
+
async function renderFromData(data, options = {}) {
|
|
38
|
+
if (options.llm) {
|
|
39
|
+
const body = await (0, llm_renderer_js_1.renderWithLLM)(data, options.llm);
|
|
40
|
+
// Always include structural CSS/JS — the LLM fallback path may produce structural HTML
|
|
41
|
+
return buildDocument(body, options, (0, renderer_js_1.getRendererCSS)(), (0, renderer_js_1.getRendererJS)());
|
|
42
|
+
}
|
|
43
|
+
const body = (0, renderer_js_1.renderJSON)(data);
|
|
44
|
+
return buildDocument(body, options, (0, renderer_js_1.getRendererCSS)(), (0, renderer_js_1.getRendererJS)());
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sync structural rendering (no LLM). Use when you know you don't need LLM.
|
|
48
|
+
*/
|
|
49
|
+
function renderFromDataSync(data, options = {}) {
|
|
50
|
+
const body = (0, renderer_js_1.renderJSON)(data);
|
|
51
|
+
return buildDocument(body, options, (0, renderer_js_1.getRendererCSS)(), (0, renderer_js_1.getRendererJS)());
|
|
52
|
+
}
|
|
53
|
+
/** Render a form from a JSON Schema (for tool input). Always sync. */
|
|
54
|
+
function renderFromSchema(schema, options = {}) {
|
|
55
|
+
const body = (0, form_js_1.renderForm)(schema, {
|
|
56
|
+
toolName: options.toolName,
|
|
57
|
+
toolDescription: options.toolDescription,
|
|
58
|
+
});
|
|
59
|
+
const playground = options.debug ? (0, playground_js_1.generatePlaygroundHTML)() : '';
|
|
60
|
+
const css = [
|
|
61
|
+
(0, theme_js_1.generateThemeCSS)(),
|
|
62
|
+
(0, utilities_js_1.generateUtilityCSS)(),
|
|
63
|
+
(0, form_js_1.getFormCSS)(),
|
|
64
|
+
options.debug ? (0, playground_js_1.getPlaygroundCSS)() : '',
|
|
65
|
+
].join('\n');
|
|
66
|
+
const js = [
|
|
67
|
+
(0, bridge_js_1.generateBridgeJS)(),
|
|
68
|
+
options.debug ? (0, playground_js_1.getPlaygroundJS)() : '',
|
|
69
|
+
].join('\n');
|
|
70
|
+
return (0, html_builder_js_1.document)({
|
|
71
|
+
title: options.title ?? options.toolName ?? 'MCP Tool',
|
|
72
|
+
css,
|
|
73
|
+
body: body + playground,
|
|
74
|
+
js,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Unified API */
|
|
78
|
+
async function render(input, options = {}) {
|
|
79
|
+
if (input.mode === 'schema') {
|
|
80
|
+
return renderFromSchema(input.schema, {
|
|
81
|
+
...options,
|
|
82
|
+
toolName: input.toolName,
|
|
83
|
+
toolDescription: input.toolDescription,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return renderFromData(input.data, {
|
|
87
|
+
...options,
|
|
88
|
+
toolName: input.toolName,
|
|
89
|
+
toolDescription: input.toolDescription,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Escape HTML special characters to prevent XSS */
|
|
2
|
+
export declare function escapeHtml(str: string): string;
|
|
3
|
+
/** Build an HTML opening tag with attributes */
|
|
4
|
+
export declare function tag(name: string, attrs?: Record<string, string | boolean | undefined>, selfClosing?: boolean): string;
|
|
5
|
+
/** Wrap content in a style tag */
|
|
6
|
+
export declare function style(css: string): string;
|
|
7
|
+
/** Wrap content in a script tag */
|
|
8
|
+
export declare function script(js: string): string;
|
|
9
|
+
/** Wrap content in a complete HTML document */
|
|
10
|
+
export declare function document(opts: {
|
|
11
|
+
title?: string;
|
|
12
|
+
css?: string;
|
|
13
|
+
js?: string;
|
|
14
|
+
body: string;
|
|
15
|
+
}): string;
|
|
16
|
+
//# sourceMappingURL=html-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-builder.d.ts","sourceRoot":"","sources":["../src/html-builder.ts"],"names":[],"mappings":"AAUA,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,gDAAgD;AAChD,wBAAgB,GAAG,CACjB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAM,EACxD,WAAW,UAAQ,GAClB,MAAM,CAOR;AAED,kCAAkC;AAClC,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,mCAAmC;AACnC,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,IAAI,EAAE;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,CAeT"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ── Safe HTML string builder with XSS prevention ──
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.escapeHtml = escapeHtml;
|
|
5
|
+
exports.tag = tag;
|
|
6
|
+
exports.style = style;
|
|
7
|
+
exports.script = script;
|
|
8
|
+
exports.document = document;
|
|
9
|
+
const ESCAPE_MAP = {
|
|
10
|
+
'&': '&',
|
|
11
|
+
'<': '<',
|
|
12
|
+
'>': '>',
|
|
13
|
+
'"': '"',
|
|
14
|
+
"'": ''',
|
|
15
|
+
};
|
|
16
|
+
/** Escape HTML special characters to prevent XSS */
|
|
17
|
+
function escapeHtml(str) {
|
|
18
|
+
return str.replace(/[&<>"']/g, (ch) => ESCAPE_MAP[ch] ?? ch);
|
|
19
|
+
}
|
|
20
|
+
/** Build an HTML opening tag with attributes */
|
|
21
|
+
function tag(name, attrs = {}, selfClosing = false) {
|
|
22
|
+
const attrStr = Object.entries(attrs)
|
|
23
|
+
.filter(([, v]) => v !== undefined && v !== false)
|
|
24
|
+
.map(([k, v]) => (v === true ? k : `${k}="${escapeHtml(String(v))}"`))
|
|
25
|
+
.join(' ');
|
|
26
|
+
const open = attrStr ? `<${name} ${attrStr}` : `<${name}`;
|
|
27
|
+
return selfClosing ? `${open} />` : `${open}>`;
|
|
28
|
+
}
|
|
29
|
+
/** Wrap content in a style tag */
|
|
30
|
+
function style(css) {
|
|
31
|
+
return `<style>\n${css}\n</style>`;
|
|
32
|
+
}
|
|
33
|
+
/** Wrap content in a script tag */
|
|
34
|
+
function script(js) {
|
|
35
|
+
return `<script>\n${js}\n</script>`;
|
|
36
|
+
}
|
|
37
|
+
/** Wrap content in a complete HTML document */
|
|
38
|
+
function document(opts) {
|
|
39
|
+
const titleTag = opts.title ? `<title>${escapeHtml(opts.title)}</title>` : '';
|
|
40
|
+
return `<!DOCTYPE html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="UTF-8">
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
45
|
+
${titleTag}
|
|
46
|
+
${opts.css ? style(opts.css) : ''}
|
|
47
|
+
</head>
|
|
48
|
+
<body>
|
|
49
|
+
${opts.body}
|
|
50
|
+
${opts.js ? script(opts.js) : ''}
|
|
51
|
+
</body>
|
|
52
|
+
</html>`;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=html-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-builder.js","sourceRoot":"","sources":["../src/html-builder.ts"],"names":[],"mappings":";AAAA,qDAAqD;;AAWrD,gCAEC;AAGD,kBAWC;AAGD,sBAEC;AAGD,wBAEC;AAGD,4BAoBC;AA1DD,MAAM,UAAU,GAA2B;IACzC,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;CACb,CAAC;AAEF,oDAAoD;AACpD,SAAgB,UAAU,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,gDAAgD;AAChD,SAAgB,GAAG,CACjB,IAAY,EACZ,QAAsD,EAAE,EACxD,WAAW,GAAG,KAAK;IAEnB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,KAAK,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SACrE,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC1D,OAAO,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;AACjD,CAAC;AAED,kCAAkC;AAClC,SAAgB,KAAK,CAAC,GAAW;IAC/B,OAAO,YAAY,GAAG,YAAY,CAAC;AACrC,CAAC;AAED,mCAAmC;AACnC,SAAgB,MAAM,CAAC,EAAU;IAC/B,OAAO,aAAa,EAAE,aAAa,CAAC;AACtC,CAAC;AAED,+CAA+C;AAC/C,SAAgB,QAAQ,CAAC,IAKxB;IACC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,OAAO;;;;;EAKP,QAAQ;EACR,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;;;EAG/B,IAAI,CAAC,IAAI;EACT,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;;QAExB,CAAC;AACT,CAAC"}
|
|
@@ -1,34 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
render,
|
|
4
|
-
renderFromSchema,
|
|
5
|
-
renderFromData,
|
|
6
|
-
renderFromDataSync,
|
|
7
|
-
} from './engine.js';
|
|
8
|
-
|
|
9
|
-
// Universal JSON → HTML renderer (structural fallback)
|
|
1
|
+
export { render, renderFromSchema, renderFromData, renderFromDataSync, } from './engine.js';
|
|
10
2
|
export { renderJSON, getRendererCSS, getRendererJS } from './renderer.js';
|
|
11
|
-
|
|
12
|
-
// LLM-powered semantic renderer
|
|
13
3
|
export { renderWithLLM, RENDERING_PROMPT } from './llm-renderer.js';
|
|
14
4
|
export type { LLMConfig } from './llm-renderer.js';
|
|
15
|
-
|
|
16
|
-
// Building blocks (for custom composition)
|
|
17
5
|
export { generateThemeCSS } from './theme.js';
|
|
18
6
|
export { generateUtilityCSS } from './utilities.js';
|
|
19
7
|
export { generateBridgeJS } from './bridge.js';
|
|
20
8
|
export { escapeHtml, tag, style, script, document } from './html-builder.js';
|
|
21
|
-
|
|
22
|
-
// Form renderer (JSON Schema → form UI)
|
|
23
9
|
export { renderForm, getFormCSS } from './renderers/form.js';
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export type {
|
|
27
|
-
RenderOptions,
|
|
28
|
-
EngineInput,
|
|
29
|
-
SchemaInput,
|
|
30
|
-
DataInput,
|
|
31
|
-
JSONSchema,
|
|
32
|
-
MCPToolDefinition,
|
|
33
|
-
MCPServerInfo,
|
|
34
|
-
} from './types.js';
|
|
10
|
+
export type { RenderOptions, EngineInput, SchemaInput, DataInput, JSONSchema, MCPToolDefinition, MCPServerInfo, } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG1E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACpE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAG7D,YAAY,EACV,aAAa,EACb,WAAW,EACX,WAAW,EACX,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFormCSS = exports.renderForm = exports.document = exports.script = exports.style = exports.tag = exports.escapeHtml = exports.generateBridgeJS = exports.generateUtilityCSS = exports.generateThemeCSS = exports.RENDERING_PROMPT = exports.renderWithLLM = exports.getRendererJS = exports.getRendererCSS = exports.renderJSON = exports.renderFromDataSync = exports.renderFromData = exports.renderFromSchema = exports.render = void 0;
|
|
4
|
+
// ── Public API ──
|
|
5
|
+
var engine_js_1 = require("./engine.js");
|
|
6
|
+
Object.defineProperty(exports, "render", { enumerable: true, get: function () { return engine_js_1.render; } });
|
|
7
|
+
Object.defineProperty(exports, "renderFromSchema", { enumerable: true, get: function () { return engine_js_1.renderFromSchema; } });
|
|
8
|
+
Object.defineProperty(exports, "renderFromData", { enumerable: true, get: function () { return engine_js_1.renderFromData; } });
|
|
9
|
+
Object.defineProperty(exports, "renderFromDataSync", { enumerable: true, get: function () { return engine_js_1.renderFromDataSync; } });
|
|
10
|
+
// Universal JSON → HTML renderer (structural fallback)
|
|
11
|
+
var renderer_js_1 = require("./renderer.js");
|
|
12
|
+
Object.defineProperty(exports, "renderJSON", { enumerable: true, get: function () { return renderer_js_1.renderJSON; } });
|
|
13
|
+
Object.defineProperty(exports, "getRendererCSS", { enumerable: true, get: function () { return renderer_js_1.getRendererCSS; } });
|
|
14
|
+
Object.defineProperty(exports, "getRendererJS", { enumerable: true, get: function () { return renderer_js_1.getRendererJS; } });
|
|
15
|
+
// LLM-powered semantic renderer
|
|
16
|
+
var llm_renderer_js_1 = require("./llm-renderer.js");
|
|
17
|
+
Object.defineProperty(exports, "renderWithLLM", { enumerable: true, get: function () { return llm_renderer_js_1.renderWithLLM; } });
|
|
18
|
+
Object.defineProperty(exports, "RENDERING_PROMPT", { enumerable: true, get: function () { return llm_renderer_js_1.RENDERING_PROMPT; } });
|
|
19
|
+
// Building blocks (for custom composition)
|
|
20
|
+
var theme_js_1 = require("./theme.js");
|
|
21
|
+
Object.defineProperty(exports, "generateThemeCSS", { enumerable: true, get: function () { return theme_js_1.generateThemeCSS; } });
|
|
22
|
+
var utilities_js_1 = require("./utilities.js");
|
|
23
|
+
Object.defineProperty(exports, "generateUtilityCSS", { enumerable: true, get: function () { return utilities_js_1.generateUtilityCSS; } });
|
|
24
|
+
var bridge_js_1 = require("./bridge.js");
|
|
25
|
+
Object.defineProperty(exports, "generateBridgeJS", { enumerable: true, get: function () { return bridge_js_1.generateBridgeJS; } });
|
|
26
|
+
var html_builder_js_1 = require("./html-builder.js");
|
|
27
|
+
Object.defineProperty(exports, "escapeHtml", { enumerable: true, get: function () { return html_builder_js_1.escapeHtml; } });
|
|
28
|
+
Object.defineProperty(exports, "tag", { enumerable: true, get: function () { return html_builder_js_1.tag; } });
|
|
29
|
+
Object.defineProperty(exports, "style", { enumerable: true, get: function () { return html_builder_js_1.style; } });
|
|
30
|
+
Object.defineProperty(exports, "script", { enumerable: true, get: function () { return html_builder_js_1.script; } });
|
|
31
|
+
Object.defineProperty(exports, "document", { enumerable: true, get: function () { return html_builder_js_1.document; } });
|
|
32
|
+
// Form renderer (JSON Schema → form UI)
|
|
33
|
+
var form_js_1 = require("./renderers/form.js");
|
|
34
|
+
Object.defineProperty(exports, "renderForm", { enumerable: true, get: function () { return form_js_1.renderForm; } });
|
|
35
|
+
Object.defineProperty(exports, "getFormCSS", { enumerable: true, get: function () { return form_js_1.getFormCSS; } });
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mBAAmB;AACnB,yCAKqB;AAJnB,mGAAA,MAAM,OAAA;AACN,6GAAA,gBAAgB,OAAA;AAChB,2GAAA,cAAc,OAAA;AACd,+GAAA,kBAAkB,OAAA;AAGpB,uDAAuD;AACvD,6CAA0E;AAAjE,yGAAA,UAAU,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,4GAAA,aAAa,OAAA;AAElD,gCAAgC;AAChC,qDAAoE;AAA3D,gHAAA,aAAa,OAAA;AAAE,mHAAA,gBAAgB,OAAA;AAGxC,2CAA2C;AAC3C,uCAA8C;AAArC,4GAAA,gBAAgB,OAAA;AACzB,+CAAoD;AAA3C,kHAAA,kBAAkB,OAAA;AAC3B,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA;AACzB,qDAA6E;AAApE,6GAAA,UAAU,OAAA;AAAE,sGAAA,GAAG,OAAA;AAAE,wGAAA,KAAK,OAAA;AAAE,yGAAA,MAAM,OAAA;AAAE,2GAAA,QAAQ,OAAA;AAEjD,wCAAwC;AACxC,+CAA6D;AAApD,qGAAA,UAAU,OAAA;AAAE,qGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM-powered semantic renderer.
|
|
3
|
+
*
|
|
4
|
+
* The structural renderer (renderer.ts) maps JSON shapes to HTML mechanically.
|
|
5
|
+
* This module sends JSON to an LLM with a rendering prompt,
|
|
6
|
+
* letting the model understand semantics and produce the best HTML.
|
|
7
|
+
*
|
|
8
|
+
* Supports any OpenAI-compatible API.
|
|
9
|
+
*/
|
|
10
|
+
/** Configuration for the LLM endpoint */
|
|
11
|
+
export interface LLMConfig {
|
|
12
|
+
/** API base URL (e.g. "http://localhost:11434/v1") */
|
|
13
|
+
apiUrl: string;
|
|
14
|
+
/** API key (optional for local models) */
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
/** Model name */
|
|
17
|
+
model: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The rendering prompt.
|
|
21
|
+
*
|
|
22
|
+
* This is intentionally short and non-prescriptive. We tell the model
|
|
23
|
+
* WHAT to do (produce the best HTML for this data), not HOW to do it
|
|
24
|
+
* (don't enumerate SVG, markdown, etc.). The model should figure out
|
|
25
|
+
* the semantics on its own.
|
|
26
|
+
*/
|
|
27
|
+
declare const SYSTEM_PROMPT = "You are a JSON-to-HTML renderer. You receive JSON data and produce an HTML fragment that visualizes it in the best way possible.\n\nRules:\n1. Output ONLY an HTML fragment. No <html>, <head>, <body> wrappers \u2014 those exist already.\n2. Understand what the data MEANS, not just its shape. Render content in its native form \u2014 if something is meant to be seen, show it; if it's meant to be read, format it; if it's structured, organize it.\n3. Use these CSS variables for theming (light/dark mode is handled automatically):\n Colors: --bg-primary, --bg-secondary, --bg-tertiary, --bg-elevated, --text-primary, --text-secondary, --text-tertiary, --accent, --accent-subtle, --success, --warning, --danger, --info (each has a -subtle variant), --border, --border-strong\n Typography: --font-sans, --font-mono, --text-xs to --text-3xl\n Spacing: --sp-1 (4px) to --sp-12 (48px)\n Radius: --radius-sm, --radius-md, --radius-lg, --radius-full\n Shadows: --shadow-sm, --shadow-md, --shadow-lg\n Utility classes: .card, .badge, .badge-success, .badge-warning, .badge-danger, .badge-info, .section-title\n4. Tailwind-compatible utility classes are available. Use them freely: flex, grid, gap-*, p-*, m-*, text-*, bg-*, border, rounded-*, shadow-*, font-*, items-*, justify-*, w-full, h-full, overflow-*, relative/absolute, etc. Responsive prefixes sm: and md: work too.\n5. Do not invent data. Do not add commentary. Just the HTML.\n6. Do not wrap output in markdown code fences.";
|
|
28
|
+
/**
|
|
29
|
+
* Render JSON data using an LLM for semantic understanding.
|
|
30
|
+
* Returns an HTML fragment (not a full document).
|
|
31
|
+
* Falls back to structural renderer on failure.
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderWithLLM(data: unknown, config: LLMConfig): Promise<string>;
|
|
34
|
+
/** Export the system prompt for inspection/customization */
|
|
35
|
+
export { SYSTEM_PROMPT as RENDERING_PROMPT };
|
|
36
|
+
//# sourceMappingURL=llm-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-renderer.d.ts","sourceRoot":"","sources":["../src/llm-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa,o9CAc4B,CAAC;AA6DhD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED,4DAA4D;AAC5D,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LLM-powered semantic renderer.
|
|
4
|
+
*
|
|
5
|
+
* The structural renderer (renderer.ts) maps JSON shapes to HTML mechanically.
|
|
6
|
+
* This module sends JSON to an LLM with a rendering prompt,
|
|
7
|
+
* letting the model understand semantics and produce the best HTML.
|
|
8
|
+
*
|
|
9
|
+
* Supports any OpenAI-compatible API.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RENDERING_PROMPT = void 0;
|
|
13
|
+
exports.renderWithLLM = renderWithLLM;
|
|
14
|
+
/**
|
|
15
|
+
* The rendering prompt.
|
|
16
|
+
*
|
|
17
|
+
* This is intentionally short and non-prescriptive. We tell the model
|
|
18
|
+
* WHAT to do (produce the best HTML for this data), not HOW to do it
|
|
19
|
+
* (don't enumerate SVG, markdown, etc.). The model should figure out
|
|
20
|
+
* the semantics on its own.
|
|
21
|
+
*/
|
|
22
|
+
const SYSTEM_PROMPT = `You are a JSON-to-HTML renderer. You receive JSON data and produce an HTML fragment that visualizes it in the best way possible.
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
1. Output ONLY an HTML fragment. No <html>, <head>, <body> wrappers — those exist already.
|
|
26
|
+
2. Understand what the data MEANS, not just its shape. Render content in its native form — if something is meant to be seen, show it; if it's meant to be read, format it; if it's structured, organize it.
|
|
27
|
+
3. Use these CSS variables for theming (light/dark mode is handled automatically):
|
|
28
|
+
Colors: --bg-primary, --bg-secondary, --bg-tertiary, --bg-elevated, --text-primary, --text-secondary, --text-tertiary, --accent, --accent-subtle, --success, --warning, --danger, --info (each has a -subtle variant), --border, --border-strong
|
|
29
|
+
Typography: --font-sans, --font-mono, --text-xs to --text-3xl
|
|
30
|
+
Spacing: --sp-1 (4px) to --sp-12 (48px)
|
|
31
|
+
Radius: --radius-sm, --radius-md, --radius-lg, --radius-full
|
|
32
|
+
Shadows: --shadow-sm, --shadow-md, --shadow-lg
|
|
33
|
+
Utility classes: .card, .badge, .badge-success, .badge-warning, .badge-danger, .badge-info, .section-title
|
|
34
|
+
4. Tailwind-compatible utility classes are available. Use them freely: flex, grid, gap-*, p-*, m-*, text-*, bg-*, border, rounded-*, shadow-*, font-*, items-*, justify-*, w-full, h-full, overflow-*, relative/absolute, etc. Responsive prefixes sm: and md: work too.
|
|
35
|
+
5. Do not invent data. Do not add commentary. Just the HTML.
|
|
36
|
+
6. Do not wrap output in markdown code fences.`;
|
|
37
|
+
exports.RENDERING_PROMPT = SYSTEM_PROMPT;
|
|
38
|
+
/**
|
|
39
|
+
* Call an OpenAI-compatible chat completions API.
|
|
40
|
+
*/
|
|
41
|
+
async function callLLM(data, config) {
|
|
42
|
+
const url = config.apiUrl.replace(/\/+$/, '') + '/chat/completions';
|
|
43
|
+
const headers = {
|
|
44
|
+
'Content-Type': 'application/json',
|
|
45
|
+
};
|
|
46
|
+
if (config.apiKey) {
|
|
47
|
+
headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
48
|
+
}
|
|
49
|
+
const body = {
|
|
50
|
+
model: config.model,
|
|
51
|
+
messages: [
|
|
52
|
+
{ role: 'system', content: SYSTEM_PROMPT },
|
|
53
|
+
{ role: 'user', content: JSON.stringify(data, null, 2) },
|
|
54
|
+
],
|
|
55
|
+
temperature: 0.2,
|
|
56
|
+
max_tokens: 16384,
|
|
57
|
+
};
|
|
58
|
+
const response = await fetch(url, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers,
|
|
61
|
+
body: JSON.stringify(body),
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const text = await response.text();
|
|
65
|
+
throw new Error(`LLM API ${response.status}: ${text.slice(0, 300)}`);
|
|
66
|
+
}
|
|
67
|
+
const result = await response.json();
|
|
68
|
+
const content = result.choices?.[0]?.message?.content;
|
|
69
|
+
if (!content) {
|
|
70
|
+
throw new Error('LLM returned empty response');
|
|
71
|
+
}
|
|
72
|
+
return stripCodeFences(content);
|
|
73
|
+
}
|
|
74
|
+
/** Remove markdown code fences if the LLM wrapped its output */
|
|
75
|
+
function stripCodeFences(html) {
|
|
76
|
+
const trimmed = html.trim();
|
|
77
|
+
const fenceMatch = trimmed.match(/^```(?:html)?\s*\n([\s\S]*?)\n\s*```$/);
|
|
78
|
+
if (fenceMatch) {
|
|
79
|
+
return fenceMatch[1].trim();
|
|
80
|
+
}
|
|
81
|
+
return trimmed;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Render JSON data using an LLM for semantic understanding.
|
|
85
|
+
* Returns an HTML fragment (not a full document).
|
|
86
|
+
* Falls back to structural renderer on failure.
|
|
87
|
+
*/
|
|
88
|
+
async function renderWithLLM(data, config) {
|
|
89
|
+
try {
|
|
90
|
+
const html = await callLLM(data, config);
|
|
91
|
+
return `<div class="mcp-root">${html}</div>`;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
95
|
+
console.error(` LLM rendering failed: ${message}`);
|
|
96
|
+
console.error(' Falling back to structural renderer.');
|
|
97
|
+
const { renderJSON } = await import('./renderer.js');
|
|
98
|
+
const fallbackHTML = renderJSON(data);
|
|
99
|
+
const errorBanner = `<div style="padding:var(--sp-3);margin-bottom:var(--sp-4);background:var(--warning-subtle);border:1px solid var(--warning);border-radius:var(--radius-sm);font-size:var(--text-sm);color:var(--text-primary)">LLM rendering failed: ${message.replace(/</g, '<')}. Showing structural fallback.</div>`;
|
|
100
|
+
return `<div class="mcp-root">${errorBanner}${fallbackHTML}</div>`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=llm-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-renderer.js","sourceRoot":"","sources":["../src/llm-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../src/playground.ts"],"names":[],"mappings":"AAGA,wBAAgB,sBAAsB,IAAI,MAAM,CA6C/C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAyDzC;AAED,wBAAgB,eAAe,IAAI,MAAM,CA6ExC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePlaygroundHTML = generatePlaygroundHTML;
|
|
4
|
+
exports.getPlaygroundCSS = getPlaygroundCSS;
|
|
5
|
+
exports.getPlaygroundJS = getPlaygroundJS;
|
|
6
|
+
function generatePlaygroundHTML() {
|
|
7
|
+
return `
|
|
6
8
|
<!-- Debug Playground -->
|
|
7
9
|
<button id="pg-toggle" class="pg-toggle" onclick="__mcpTogglePg()"></> Debug Playground</button>
|
|
8
10
|
<div id="pg-panel" class="pg-panel hidden">
|
|
@@ -47,9 +49,8 @@ export function generatePlaygroundHTML(): string {
|
|
|
47
49
|
</div>
|
|
48
50
|
</div>`;
|
|
49
51
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return `
|
|
52
|
+
function getPlaygroundCSS() {
|
|
53
|
+
return `
|
|
53
54
|
.pg-toggle {
|
|
54
55
|
position: fixed; bottom: 16px; right: 16px; z-index: 9998;
|
|
55
56
|
padding: 8px 16px; border-radius: var(--radius-full);
|
|
@@ -106,9 +107,8 @@ export function getPlaygroundCSS(): string {
|
|
|
106
107
|
.pg-json { font-family: var(--font-mono); font-size: var(--text-xs); }
|
|
107
108
|
`;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return `
|
|
110
|
+
function getPlaygroundJS() {
|
|
111
|
+
return `
|
|
112
112
|
// ── Playground Logic ──
|
|
113
113
|
(function() {
|
|
114
114
|
// Load saved config from localStorage
|
|
@@ -185,3 +185,4 @@ export function getPlaygroundJS(): string {
|
|
|
185
185
|
})();
|
|
186
186
|
`;
|
|
187
187
|
}
|
|
188
|
+
//# sourceMappingURL=playground.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground.js","sourceRoot":"","sources":["../src/playground.ts"],"names":[],"mappings":";;AAGA,wDA6CC;AAED,4CAyDC;AAED,0CA6EC;AAvLD,SAAgB,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CF,CAAC;AACR,CAAC;AAED,SAAgB,gBAAgB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDR,CAAC;AACF,CAAC;AAED,SAAgB,eAAe;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ER,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Render any JSON data as an HTML fragment. No business logic, pure structure. */
|
|
2
|
+
export declare function renderJSON(data: unknown): string;
|
|
3
|
+
/** Get the CSS for the universal renderer */
|
|
4
|
+
export declare function getRendererCSS(): string;
|
|
5
|
+
/** Get the JS for table sorting (supports multiple tables) */
|
|
6
|
+
export declare function getRendererJS(): string;
|
|
7
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAgQA,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAGhD;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,IAAI,MAAM,CAwFvC;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,IAAI,MAAM,CAyBtC"}
|