@wireweave/markdown-plugin 1.0.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/README.md +273 -0
- package/dist/index.cjs +162 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown-it.cjs +122 -0
- package/dist/markdown-it.cjs.map +1 -0
- package/dist/markdown-it.d.cts +113 -0
- package/dist/markdown-it.d.ts +113 -0
- package/dist/markdown-it.js +101 -0
- package/dist/markdown-it.js.map +1 -0
- package/dist/marked.cjs +120 -0
- package/dist/marked.cjs.map +1 -0
- package/dist/marked.d.cts +3 -0
- package/dist/marked.d.ts +3 -0
- package/dist/marked.js +99 -0
- package/dist/marked.js.map +1 -0
- package/dist/remarkable.cjs +126 -0
- package/dist/remarkable.cjs.map +1 -0
- package/dist/remarkable.d.cts +3 -0
- package/dist/remarkable.d.ts +3 -0
- package/dist/remarkable.js +105 -0
- package/dist/remarkable.js.map +1 -0
- package/package.json +86 -0
- package/src/index.ts +163 -0
- package/src/markdown-it.ts +43 -0
- package/src/marked.ts +34 -0
- package/src/remarkable.ts +84 -0
package/dist/marked.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
parse,
|
|
4
|
+
render,
|
|
5
|
+
renderToSvg,
|
|
6
|
+
resolveViewport,
|
|
7
|
+
wrapInPreviewContainer
|
|
8
|
+
} from "@wireweave/core";
|
|
9
|
+
var defaultOptions = {
|
|
10
|
+
format: "svg-img",
|
|
11
|
+
theme: "light",
|
|
12
|
+
containerClass: "wireframe-container",
|
|
13
|
+
errorHandling: "both",
|
|
14
|
+
containerWidth: 0,
|
|
15
|
+
// 0 means no scaling
|
|
16
|
+
maxScale: 1
|
|
17
|
+
};
|
|
18
|
+
function renderWireframe(code, options = {}) {
|
|
19
|
+
const opts = { ...defaultOptions, ...options };
|
|
20
|
+
try {
|
|
21
|
+
const doc = parse(code);
|
|
22
|
+
switch (opts.format) {
|
|
23
|
+
case "html": {
|
|
24
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
25
|
+
return `
|
|
26
|
+
<div class="${opts.containerClass}">
|
|
27
|
+
<style>${css}</style>
|
|
28
|
+
${html}
|
|
29
|
+
</div>
|
|
30
|
+
`.trim();
|
|
31
|
+
}
|
|
32
|
+
case "html-preview": {
|
|
33
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
34
|
+
const firstPage = doc.children[0];
|
|
35
|
+
const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);
|
|
36
|
+
const previewHtml = wrapInPreviewContainer(html, viewport, {
|
|
37
|
+
darkMode: opts.theme === "dark",
|
|
38
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
|
|
39
|
+
});
|
|
40
|
+
return `
|
|
41
|
+
<div class="${opts.containerClass}">
|
|
42
|
+
<style>${css}</style>
|
|
43
|
+
${previewHtml}
|
|
44
|
+
</div>
|
|
45
|
+
`.trim();
|
|
46
|
+
}
|
|
47
|
+
case "svg": {
|
|
48
|
+
const { svg } = renderToSvg(doc);
|
|
49
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
50
|
+
}
|
|
51
|
+
case "svg-img":
|
|
52
|
+
default: {
|
|
53
|
+
const { svg } = renderToSvg(doc);
|
|
54
|
+
const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
|
|
55
|
+
return `
|
|
56
|
+
<div class="${opts.containerClass}">
|
|
57
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
58
|
+
</div>
|
|
59
|
+
`.trim();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return renderError(code, error, opts);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function renderError(code, error, options) {
|
|
67
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml(error.message)}</pre>`;
|
|
68
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml(code)}</code></pre>`;
|
|
69
|
+
switch (options.errorHandling) {
|
|
70
|
+
case "code":
|
|
71
|
+
return codeHtml;
|
|
72
|
+
case "error":
|
|
73
|
+
return errorHtml;
|
|
74
|
+
case "both":
|
|
75
|
+
default:
|
|
76
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function escapeHtml(text) {
|
|
80
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/marked.ts
|
|
84
|
+
function markedWireframe(options = {}) {
|
|
85
|
+
return {
|
|
86
|
+
renderer: {
|
|
87
|
+
code(token) {
|
|
88
|
+
if (token.lang === "wireframe" || token.lang === "wf") {
|
|
89
|
+
return renderWireframe(token.text, options);
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
markedWireframe
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=marked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/marked.ts"],"sourcesContent":["/**\n * @wireweave/markdown-plugin\n *\n * Markdown plugins for wireweave\n */\n\nimport {\n parse,\n render,\n renderToSvg,\n resolveViewport,\n wrapInPreviewContainer,\n} from '@wireweave/core';\n\nexport interface WireframePluginOptions {\n /**\n * Output format\n * - 'html': HTML/CSS rendering (inline styles)\n * - 'html-preview': HTML with preview container (supports scaling)\n * - 'svg': SVG image\n * - 'svg-img': base64 encoded img tag\n */\n format?: 'html' | 'html-preview' | 'svg' | 'svg-img';\n\n /**\n * Theme for rendering\n * - 'light': Light theme\n * - 'dark': Dark theme\n */\n theme?: 'light' | 'dark';\n\n /**\n * Container class for wrapping SVG/HTML\n */\n containerClass?: string;\n\n /**\n * Error handling mode\n * - 'code': Show original code\n * - 'error': Show error message\n * - 'both': Show both\n */\n errorHandling?: 'code' | 'error' | 'both';\n\n /**\n * Container width for preview scaling (in pixels)\n * When set, the wireframe will be scaled to fit this width\n */\n containerWidth?: number;\n\n /**\n * Maximum scale factor (default: 1)\n * Prevents the preview from being scaled up beyond this value\n */\n maxScale?: number;\n}\n\nconst defaultOptions: Required<WireframePluginOptions> = {\n format: 'svg-img',\n theme: 'light',\n containerClass: 'wireframe-container',\n errorHandling: 'both',\n containerWidth: 0, // 0 means no scaling\n maxScale: 1,\n};\n\n/**\n * Render wireframe code to output format\n */\nexport function renderWireframe(\n code: string,\n options: WireframePluginOptions = {}\n): string {\n const opts = { ...defaultOptions, ...options };\n\n try {\n const doc = parse(code);\n\n switch (opts.format) {\n case 'html': {\n const { html, css } = render(doc, { theme: opts.theme });\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${html}\n </div>\n `.trim();\n }\n\n case 'html-preview': {\n const { html, css } = render(doc, { theme: opts.theme });\n const firstPage = doc.children[0];\n const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);\n\n const previewHtml = wrapInPreviewContainer(html, viewport, {\n darkMode: opts.theme === 'dark',\n containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,\n });\n\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${previewHtml}\n </div>\n `.trim();\n }\n\n case 'svg': {\n const { svg } = renderToSvg(doc);\n return `<div class=\"${opts.containerClass}\">${svg}</div>`;\n }\n\n case 'svg-img':\n default: {\n const { svg } = renderToSvg(doc);\n // Use btoa for browser compatibility, Buffer for Node.js\n const base64 =\n typeof Buffer !== 'undefined'\n ? Buffer.from(svg).toString('base64')\n : btoa(svg);\n return `\n <div class=\"${opts.containerClass}\">\n <img src=\"data:image/svg+xml;base64,${base64}\" alt=\"Wireframe\" />\n </div>\n `.trim();\n }\n }\n } catch (error) {\n return renderError(code, error as Error, opts);\n }\n}\n\nfunction renderError(\n code: string,\n error: Error,\n options: Required<WireframePluginOptions>\n): string {\n const errorHtml = `<pre class=\"wireframe-error\">${escapeHtml(error.message)}</pre>`;\n const codeHtml = `<pre class=\"wireframe-source\"><code>${escapeHtml(code)}</code></pre>`;\n\n switch (options.errorHandling) {\n case 'code':\n return codeHtml;\n case 'error':\n return errorHtml;\n case 'both':\n default:\n return `<div class=\"${options.containerClass} wireframe-error-container\">${errorHtml}${codeHtml}</div>`;\n }\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nexport { markdownItWireframe } from './markdown-it';\nexport { markedWireframe } from './marked';\nexport { remarkableWireframe } from './remarkable';\n","/**\n * marked extension for wireweave\n */\n\nimport type { MarkedExtension, Tokens } from 'marked';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * marked extension\n *\n * @example\n * ```typescript\n * import { marked } from 'marked';\n * import { markedWireframe } from '@wireweave/markdown-plugin/marked';\n *\n * marked.use(markedWireframe({ format: 'svg' }));\n *\n * const html = marked.parse('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markedWireframe(\n options: WireframePluginOptions = {}\n): MarkedExtension {\n return {\n renderer: {\n code(token: Tokens.Code): string | false {\n if (token.lang === 'wireframe' || token.lang === 'wf') {\n return renderWireframe(token.text, options);\n }\n return false; // Use default renderer\n },\n },\n };\n}\n"],"mappings":";AAMA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA6CP,IAAM,iBAAmD;AAAA,EACvD,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAChB,UAAU;AACZ;AAKO,SAAS,gBACd,MACA,UAAkC,CAAC,GAC3B;AACR,QAAM,OAAO,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAE7C,MAAI;AACF,UAAM,MAAM,MAAM,IAAI;AAEtB,YAAQ,KAAK,QAAQ;AAAA,MACnB,KAAK,QAAQ;AACX,cAAM,EAAE,MAAM,IAAI,IAAI,OAAO,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AACvD,eAAO;AAAA,wBACS,KAAK,cAAc;AAAA,qBACtB,GAAG;AAAA,cACV,IAAI;AAAA;AAAA,UAER,KAAK;AAAA,MACT;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,EAAE,MAAM,IAAI,IAAI,OAAO,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AACvD,cAAM,YAAY,IAAI,SAAS,CAAC;AAChC,cAAM,WAAW,gBAAgB,WAAW,UAAU,WAAW,MAAM;AAEvE,cAAM,cAAc,uBAAuB,MAAM,UAAU;AAAA,UACzD,UAAU,KAAK,UAAU;AAAA,UACzB,gBAAgB,KAAK,iBAAiB,IAAI,KAAK,iBAAiB;AAAA,QAClE,CAAC;AAED,eAAO;AAAA,wBACS,KAAK,cAAc;AAAA,qBACtB,GAAG;AAAA,cACV,WAAW;AAAA;AAAA,UAEf,KAAK;AAAA,MACT;AAAA,MAEA,KAAK,OAAO;AACV,cAAM,EAAE,IAAI,IAAI,YAAY,GAAG;AAC/B,eAAO,eAAe,KAAK,cAAc,KAAK,GAAG;AAAA,MACnD;AAAA,MAEA,KAAK;AAAA,MACL,SAAS;AACP,cAAM,EAAE,IAAI,IAAI,YAAY,GAAG;AAE/B,cAAM,SACJ,OAAO,WAAW,cACd,OAAO,KAAK,GAAG,EAAE,SAAS,QAAQ,IAClC,KAAK,GAAG;AACd,eAAO;AAAA,wBACS,KAAK,cAAc;AAAA,kDACO,MAAM;AAAA;AAAA,UAE9C,KAAK;AAAA,MACT;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,WAAO,YAAY,MAAM,OAAgB,IAAI;AAAA,EAC/C;AACF;AAEA,SAAS,YACP,MACA,OACA,SACQ;AACR,QAAM,YAAY,gCAAgC,WAAW,MAAM,OAAO,CAAC;AAC3E,QAAM,WAAW,uCAAuC,WAAW,IAAI,CAAC;AAExE,UAAQ,QAAQ,eAAe;AAAA,IAC7B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO,eAAe,QAAQ,cAAc,+BAA+B,SAAS,GAAG,QAAQ;AAAA,EACnG;AACF;AAEA,SAAS,WAAW,MAAsB;AACxC,SAAO,KACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;;;AC1IO,SAAS,gBACd,UAAkC,CAAC,GAClB;AACjB,SAAO;AAAA,IACL,UAAU;AAAA,MACR,KAAK,OAAoC;AACvC,YAAI,MAAM,SAAS,eAAe,MAAM,SAAS,MAAM;AACrD,iBAAO,gBAAgB,MAAM,MAAM,OAAO;AAAA,QAC5C;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/remarkable.ts
|
|
21
|
+
var remarkable_exports = {};
|
|
22
|
+
__export(remarkable_exports, {
|
|
23
|
+
remarkableWireframe: () => remarkableWireframe
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(remarkable_exports);
|
|
26
|
+
|
|
27
|
+
// src/index.ts
|
|
28
|
+
var import_core = require("@wireweave/core");
|
|
29
|
+
var defaultOptions = {
|
|
30
|
+
format: "svg-img",
|
|
31
|
+
theme: "light",
|
|
32
|
+
containerClass: "wireframe-container",
|
|
33
|
+
errorHandling: "both",
|
|
34
|
+
containerWidth: 0,
|
|
35
|
+
// 0 means no scaling
|
|
36
|
+
maxScale: 1
|
|
37
|
+
};
|
|
38
|
+
function renderWireframe(code, options = {}) {
|
|
39
|
+
const opts = { ...defaultOptions, ...options };
|
|
40
|
+
try {
|
|
41
|
+
const doc = (0, import_core.parse)(code);
|
|
42
|
+
switch (opts.format) {
|
|
43
|
+
case "html": {
|
|
44
|
+
const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
|
|
45
|
+
return `
|
|
46
|
+
<div class="${opts.containerClass}">
|
|
47
|
+
<style>${css}</style>
|
|
48
|
+
${html}
|
|
49
|
+
</div>
|
|
50
|
+
`.trim();
|
|
51
|
+
}
|
|
52
|
+
case "html-preview": {
|
|
53
|
+
const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
|
|
54
|
+
const firstPage = doc.children[0];
|
|
55
|
+
const viewport = (0, import_core.resolveViewport)(firstPage?.viewport, firstPage?.device);
|
|
56
|
+
const previewHtml = (0, import_core.wrapInPreviewContainer)(html, viewport, {
|
|
57
|
+
darkMode: opts.theme === "dark",
|
|
58
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
|
|
59
|
+
});
|
|
60
|
+
return `
|
|
61
|
+
<div class="${opts.containerClass}">
|
|
62
|
+
<style>${css}</style>
|
|
63
|
+
${previewHtml}
|
|
64
|
+
</div>
|
|
65
|
+
`.trim();
|
|
66
|
+
}
|
|
67
|
+
case "svg": {
|
|
68
|
+
const { svg } = (0, import_core.renderToSvg)(doc);
|
|
69
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
70
|
+
}
|
|
71
|
+
case "svg-img":
|
|
72
|
+
default: {
|
|
73
|
+
const { svg } = (0, import_core.renderToSvg)(doc);
|
|
74
|
+
const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
|
|
75
|
+
return `
|
|
76
|
+
<div class="${opts.containerClass}">
|
|
77
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
78
|
+
</div>
|
|
79
|
+
`.trim();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return renderError(code, error, opts);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function renderError(code, error, options) {
|
|
87
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml(error.message)}</pre>`;
|
|
88
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml(code)}</code></pre>`;
|
|
89
|
+
switch (options.errorHandling) {
|
|
90
|
+
case "code":
|
|
91
|
+
return codeHtml;
|
|
92
|
+
case "error":
|
|
93
|
+
return errorHtml;
|
|
94
|
+
case "both":
|
|
95
|
+
default:
|
|
96
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function escapeHtml(text) {
|
|
100
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/remarkable.ts
|
|
104
|
+
function escapeHtml2(text) {
|
|
105
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
106
|
+
}
|
|
107
|
+
function remarkableWireframe(options = {}) {
|
|
108
|
+
return (md) => {
|
|
109
|
+
const rules = md.renderer.rules;
|
|
110
|
+
rules.fence = (tokens, idx, _opts, _env) => {
|
|
111
|
+
const token = tokens[idx];
|
|
112
|
+
const lang = token.params || "";
|
|
113
|
+
if (lang === "wireframe" || lang === "wf") {
|
|
114
|
+
return renderWireframe(token.content, options);
|
|
115
|
+
}
|
|
116
|
+
const langClass = lang ? ` class="language-${escapeHtml2(lang)}"` : "";
|
|
117
|
+
return `<pre><code${langClass}>${escapeHtml2(token.content)}</code></pre>
|
|
118
|
+
`;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
123
|
+
0 && (module.exports = {
|
|
124
|
+
remarkableWireframe
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=remarkable.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/remarkable.ts","../src/index.ts"],"sourcesContent":["/**\n * remarkable plugin for wireweave\n */\n\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n// Type declarations for remarkable (no @types/remarkable available)\ninterface RemarkableToken {\n type: string;\n params: string;\n content: string;\n}\n\ninterface RemarkableRenderer {\n rules: {\n fence: (\n tokens: RemarkableToken[],\n idx: number,\n options: Record<string, unknown>,\n env: Record<string, unknown>\n ) => string;\n };\n}\n\ninterface RemarkableUtils {\n escapeHtml: (text: string) => string;\n}\n\ninterface Remarkable {\n renderer: RemarkableRenderer;\n utils: RemarkableUtils;\n}\n\n/**\n * remarkable plugin\n *\n * @example\n * ```typescript\n * import { Remarkable } from 'remarkable';\n * import { remarkableWireframe } from '@wireweave/markdown-plugin/remarkable';\n *\n * const md = new Remarkable();\n * md.use(remarkableWireframe({ format: 'svg' }));\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\n/**\n * Escape HTML entities\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function remarkableWireframe(\n options: WireframePluginOptions = {}\n): (md: Remarkable) => void {\n return (md: Remarkable) => {\n const rules = md.renderer.rules;\n\n // Override fence rule completely\n rules.fence = (\n tokens: RemarkableToken[],\n idx: number,\n _opts: Record<string, unknown>,\n _env: Record<string, unknown>\n ): string => {\n const token = tokens[idx];\n const lang = token.params || '';\n\n if (lang === 'wireframe' || lang === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Render other code blocks with syntax highlighting class\n const langClass = lang ? ` class=\"language-${escapeHtml(lang)}\"` : '';\n return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>\\n`;\n };\n };\n}\n","/**\n * @wireweave/markdown-plugin\n *\n * Markdown plugins for wireweave\n */\n\nimport {\n parse,\n render,\n renderToSvg,\n resolveViewport,\n wrapInPreviewContainer,\n} from '@wireweave/core';\n\nexport interface WireframePluginOptions {\n /**\n * Output format\n * - 'html': HTML/CSS rendering (inline styles)\n * - 'html-preview': HTML with preview container (supports scaling)\n * - 'svg': SVG image\n * - 'svg-img': base64 encoded img tag\n */\n format?: 'html' | 'html-preview' | 'svg' | 'svg-img';\n\n /**\n * Theme for rendering\n * - 'light': Light theme\n * - 'dark': Dark theme\n */\n theme?: 'light' | 'dark';\n\n /**\n * Container class for wrapping SVG/HTML\n */\n containerClass?: string;\n\n /**\n * Error handling mode\n * - 'code': Show original code\n * - 'error': Show error message\n * - 'both': Show both\n */\n errorHandling?: 'code' | 'error' | 'both';\n\n /**\n * Container width for preview scaling (in pixels)\n * When set, the wireframe will be scaled to fit this width\n */\n containerWidth?: number;\n\n /**\n * Maximum scale factor (default: 1)\n * Prevents the preview from being scaled up beyond this value\n */\n maxScale?: number;\n}\n\nconst defaultOptions: Required<WireframePluginOptions> = {\n format: 'svg-img',\n theme: 'light',\n containerClass: 'wireframe-container',\n errorHandling: 'both',\n containerWidth: 0, // 0 means no scaling\n maxScale: 1,\n};\n\n/**\n * Render wireframe code to output format\n */\nexport function renderWireframe(\n code: string,\n options: WireframePluginOptions = {}\n): string {\n const opts = { ...defaultOptions, ...options };\n\n try {\n const doc = parse(code);\n\n switch (opts.format) {\n case 'html': {\n const { html, css } = render(doc, { theme: opts.theme });\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${html}\n </div>\n `.trim();\n }\n\n case 'html-preview': {\n const { html, css } = render(doc, { theme: opts.theme });\n const firstPage = doc.children[0];\n const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);\n\n const previewHtml = wrapInPreviewContainer(html, viewport, {\n darkMode: opts.theme === 'dark',\n containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,\n });\n\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${previewHtml}\n </div>\n `.trim();\n }\n\n case 'svg': {\n const { svg } = renderToSvg(doc);\n return `<div class=\"${opts.containerClass}\">${svg}</div>`;\n }\n\n case 'svg-img':\n default: {\n const { svg } = renderToSvg(doc);\n // Use btoa for browser compatibility, Buffer for Node.js\n const base64 =\n typeof Buffer !== 'undefined'\n ? Buffer.from(svg).toString('base64')\n : btoa(svg);\n return `\n <div class=\"${opts.containerClass}\">\n <img src=\"data:image/svg+xml;base64,${base64}\" alt=\"Wireframe\" />\n </div>\n `.trim();\n }\n }\n } catch (error) {\n return renderError(code, error as Error, opts);\n }\n}\n\nfunction renderError(\n code: string,\n error: Error,\n options: Required<WireframePluginOptions>\n): string {\n const errorHtml = `<pre class=\"wireframe-error\">${escapeHtml(error.message)}</pre>`;\n const codeHtml = `<pre class=\"wireframe-source\"><code>${escapeHtml(code)}</code></pre>`;\n\n switch (options.errorHandling) {\n case 'code':\n return codeHtml;\n case 'error':\n return errorHtml;\n case 'both':\n default:\n return `<div class=\"${options.containerClass} wireframe-error-container\">${errorHtml}${codeHtml}</div>`;\n }\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nexport { markdownItWireframe } from './markdown-it';\nexport { markedWireframe } from './marked';\nexport { remarkableWireframe } from './remarkable';\n"],"mappings":"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","names":["escapeHtml"]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
parse,
|
|
4
|
+
render,
|
|
5
|
+
renderToSvg,
|
|
6
|
+
resolveViewport,
|
|
7
|
+
wrapInPreviewContainer
|
|
8
|
+
} from "@wireweave/core";
|
|
9
|
+
var defaultOptions = {
|
|
10
|
+
format: "svg-img",
|
|
11
|
+
theme: "light",
|
|
12
|
+
containerClass: "wireframe-container",
|
|
13
|
+
errorHandling: "both",
|
|
14
|
+
containerWidth: 0,
|
|
15
|
+
// 0 means no scaling
|
|
16
|
+
maxScale: 1
|
|
17
|
+
};
|
|
18
|
+
function renderWireframe(code, options = {}) {
|
|
19
|
+
const opts = { ...defaultOptions, ...options };
|
|
20
|
+
try {
|
|
21
|
+
const doc = parse(code);
|
|
22
|
+
switch (opts.format) {
|
|
23
|
+
case "html": {
|
|
24
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
25
|
+
return `
|
|
26
|
+
<div class="${opts.containerClass}">
|
|
27
|
+
<style>${css}</style>
|
|
28
|
+
${html}
|
|
29
|
+
</div>
|
|
30
|
+
`.trim();
|
|
31
|
+
}
|
|
32
|
+
case "html-preview": {
|
|
33
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
34
|
+
const firstPage = doc.children[0];
|
|
35
|
+
const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);
|
|
36
|
+
const previewHtml = wrapInPreviewContainer(html, viewport, {
|
|
37
|
+
darkMode: opts.theme === "dark",
|
|
38
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
|
|
39
|
+
});
|
|
40
|
+
return `
|
|
41
|
+
<div class="${opts.containerClass}">
|
|
42
|
+
<style>${css}</style>
|
|
43
|
+
${previewHtml}
|
|
44
|
+
</div>
|
|
45
|
+
`.trim();
|
|
46
|
+
}
|
|
47
|
+
case "svg": {
|
|
48
|
+
const { svg } = renderToSvg(doc);
|
|
49
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
50
|
+
}
|
|
51
|
+
case "svg-img":
|
|
52
|
+
default: {
|
|
53
|
+
const { svg } = renderToSvg(doc);
|
|
54
|
+
const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
|
|
55
|
+
return `
|
|
56
|
+
<div class="${opts.containerClass}">
|
|
57
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
58
|
+
</div>
|
|
59
|
+
`.trim();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return renderError(code, error, opts);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function renderError(code, error, options) {
|
|
67
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml(error.message)}</pre>`;
|
|
68
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml(code)}</code></pre>`;
|
|
69
|
+
switch (options.errorHandling) {
|
|
70
|
+
case "code":
|
|
71
|
+
return codeHtml;
|
|
72
|
+
case "error":
|
|
73
|
+
return errorHtml;
|
|
74
|
+
case "both":
|
|
75
|
+
default:
|
|
76
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function escapeHtml(text) {
|
|
80
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/remarkable.ts
|
|
84
|
+
function escapeHtml2(text) {
|
|
85
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
86
|
+
}
|
|
87
|
+
function remarkableWireframe(options = {}) {
|
|
88
|
+
return (md) => {
|
|
89
|
+
const rules = md.renderer.rules;
|
|
90
|
+
rules.fence = (tokens, idx, _opts, _env) => {
|
|
91
|
+
const token = tokens[idx];
|
|
92
|
+
const lang = token.params || "";
|
|
93
|
+
if (lang === "wireframe" || lang === "wf") {
|
|
94
|
+
return renderWireframe(token.content, options);
|
|
95
|
+
}
|
|
96
|
+
const langClass = lang ? ` class="language-${escapeHtml2(lang)}"` : "";
|
|
97
|
+
return `<pre><code${langClass}>${escapeHtml2(token.content)}</code></pre>
|
|
98
|
+
`;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export {
|
|
103
|
+
remarkableWireframe
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=remarkable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/remarkable.ts"],"sourcesContent":["/**\n * @wireweave/markdown-plugin\n *\n * Markdown plugins for wireweave\n */\n\nimport {\n parse,\n render,\n renderToSvg,\n resolveViewport,\n wrapInPreviewContainer,\n} from '@wireweave/core';\n\nexport interface WireframePluginOptions {\n /**\n * Output format\n * - 'html': HTML/CSS rendering (inline styles)\n * - 'html-preview': HTML with preview container (supports scaling)\n * - 'svg': SVG image\n * - 'svg-img': base64 encoded img tag\n */\n format?: 'html' | 'html-preview' | 'svg' | 'svg-img';\n\n /**\n * Theme for rendering\n * - 'light': Light theme\n * - 'dark': Dark theme\n */\n theme?: 'light' | 'dark';\n\n /**\n * Container class for wrapping SVG/HTML\n */\n containerClass?: string;\n\n /**\n * Error handling mode\n * - 'code': Show original code\n * - 'error': Show error message\n * - 'both': Show both\n */\n errorHandling?: 'code' | 'error' | 'both';\n\n /**\n * Container width for preview scaling (in pixels)\n * When set, the wireframe will be scaled to fit this width\n */\n containerWidth?: number;\n\n /**\n * Maximum scale factor (default: 1)\n * Prevents the preview from being scaled up beyond this value\n */\n maxScale?: number;\n}\n\nconst defaultOptions: Required<WireframePluginOptions> = {\n format: 'svg-img',\n theme: 'light',\n containerClass: 'wireframe-container',\n errorHandling: 'both',\n containerWidth: 0, // 0 means no scaling\n maxScale: 1,\n};\n\n/**\n * Render wireframe code to output format\n */\nexport function renderWireframe(\n code: string,\n options: WireframePluginOptions = {}\n): string {\n const opts = { ...defaultOptions, ...options };\n\n try {\n const doc = parse(code);\n\n switch (opts.format) {\n case 'html': {\n const { html, css } = render(doc, { theme: opts.theme });\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${html}\n </div>\n `.trim();\n }\n\n case 'html-preview': {\n const { html, css } = render(doc, { theme: opts.theme });\n const firstPage = doc.children[0];\n const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);\n\n const previewHtml = wrapInPreviewContainer(html, viewport, {\n darkMode: opts.theme === 'dark',\n containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,\n });\n\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${previewHtml}\n </div>\n `.trim();\n }\n\n case 'svg': {\n const { svg } = renderToSvg(doc);\n return `<div class=\"${opts.containerClass}\">${svg}</div>`;\n }\n\n case 'svg-img':\n default: {\n const { svg } = renderToSvg(doc);\n // Use btoa for browser compatibility, Buffer for Node.js\n const base64 =\n typeof Buffer !== 'undefined'\n ? Buffer.from(svg).toString('base64')\n : btoa(svg);\n return `\n <div class=\"${opts.containerClass}\">\n <img src=\"data:image/svg+xml;base64,${base64}\" alt=\"Wireframe\" />\n </div>\n `.trim();\n }\n }\n } catch (error) {\n return renderError(code, error as Error, opts);\n }\n}\n\nfunction renderError(\n code: string,\n error: Error,\n options: Required<WireframePluginOptions>\n): string {\n const errorHtml = `<pre class=\"wireframe-error\">${escapeHtml(error.message)}</pre>`;\n const codeHtml = `<pre class=\"wireframe-source\"><code>${escapeHtml(code)}</code></pre>`;\n\n switch (options.errorHandling) {\n case 'code':\n return codeHtml;\n case 'error':\n return errorHtml;\n case 'both':\n default:\n return `<div class=\"${options.containerClass} wireframe-error-container\">${errorHtml}${codeHtml}</div>`;\n }\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nexport { markdownItWireframe } from './markdown-it';\nexport { markedWireframe } from './marked';\nexport { remarkableWireframe } from './remarkable';\n","/**\n * remarkable plugin for wireweave\n */\n\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n// Type declarations for remarkable (no @types/remarkable available)\ninterface RemarkableToken {\n type: string;\n params: string;\n content: string;\n}\n\ninterface RemarkableRenderer {\n rules: {\n fence: (\n tokens: RemarkableToken[],\n idx: number,\n options: Record<string, unknown>,\n env: Record<string, unknown>\n ) => string;\n };\n}\n\ninterface RemarkableUtils {\n escapeHtml: (text: string) => string;\n}\n\ninterface Remarkable {\n renderer: RemarkableRenderer;\n utils: RemarkableUtils;\n}\n\n/**\n * remarkable plugin\n *\n * @example\n * ```typescript\n * import { Remarkable } from 'remarkable';\n * import { remarkableWireframe } from '@wireweave/markdown-plugin/remarkable';\n *\n * const md = new Remarkable();\n * md.use(remarkableWireframe({ format: 'svg' }));\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\n/**\n * Escape HTML entities\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function remarkableWireframe(\n options: WireframePluginOptions = {}\n): (md: Remarkable) => void {\n return (md: Remarkable) => {\n const rules = md.renderer.rules;\n\n // Override fence rule completely\n rules.fence = (\n tokens: RemarkableToken[],\n idx: number,\n _opts: Record<string, unknown>,\n _env: Record<string, unknown>\n ): string => {\n const token = tokens[idx];\n const lang = token.params || '';\n\n if (lang === 'wireframe' || lang === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Render other code blocks with syntax highlighting class\n const langClass = lang ? ` class=\"language-${escapeHtml(lang)}\"` : '';\n return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>\\n`;\n };\n };\n}\n"],"mappings":"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","names":["escapeHtml"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wireweave/markdown-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Markdown plugins for wireweave",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./markdown-it": {
|
|
16
|
+
"types": "./dist/markdown-it.d.ts",
|
|
17
|
+
"import": "./dist/markdown-it.js",
|
|
18
|
+
"require": "./dist/markdown-it.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./marked": {
|
|
21
|
+
"types": "./dist/marked.d.ts",
|
|
22
|
+
"import": "./dist/marked.js",
|
|
23
|
+
"require": "./dist/marked.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./remarkable": {
|
|
26
|
+
"types": "./dist/remarkable.d.ts",
|
|
27
|
+
"import": "./dist/remarkable.js",
|
|
28
|
+
"require": "./dist/remarkable.cjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"src"
|
|
34
|
+
],
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"markdown-it": ">=12.0.0",
|
|
37
|
+
"marked": ">=4.0.0",
|
|
38
|
+
"remarkable": ">=2.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"markdown-it": {
|
|
42
|
+
"optional": true
|
|
43
|
+
},
|
|
44
|
+
"marked": {
|
|
45
|
+
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"remarkable": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@wireweave/core": "1.1.0-beta.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@release-it/conventional-changelog": "^10.0.4",
|
|
56
|
+
"@types/markdown-it": "^14.1.2",
|
|
57
|
+
"markdown-it": "^14.1.0",
|
|
58
|
+
"marked": "^15.0.6",
|
|
59
|
+
"release-it": "^19.2.3",
|
|
60
|
+
"remarkable": "^2.0.1",
|
|
61
|
+
"tsup": "^8.3.5",
|
|
62
|
+
"typescript": "^5.7.2",
|
|
63
|
+
"vitest": "^3.1.1"
|
|
64
|
+
},
|
|
65
|
+
"keywords": [
|
|
66
|
+
"wireframe",
|
|
67
|
+
"markdown",
|
|
68
|
+
"plugin",
|
|
69
|
+
"markdown-it",
|
|
70
|
+
"marked",
|
|
71
|
+
"remarkable"
|
|
72
|
+
],
|
|
73
|
+
"author": "",
|
|
74
|
+
"license": "MIT",
|
|
75
|
+
"repository": {
|
|
76
|
+
"type": "git",
|
|
77
|
+
"url": "https://github.com/wireweave/markdown-plugin.git"
|
|
78
|
+
},
|
|
79
|
+
"scripts": {
|
|
80
|
+
"build": "tsup",
|
|
81
|
+
"test": "vitest run",
|
|
82
|
+
"test:watch": "vitest",
|
|
83
|
+
"clean": "rm -rf dist",
|
|
84
|
+
"release": "release-it"
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @wireweave/markdown-plugin
|
|
3
|
+
*
|
|
4
|
+
* Markdown plugins for wireweave
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
parse,
|
|
9
|
+
render,
|
|
10
|
+
renderToSvg,
|
|
11
|
+
resolveViewport,
|
|
12
|
+
wrapInPreviewContainer,
|
|
13
|
+
} from '@wireweave/core';
|
|
14
|
+
|
|
15
|
+
export interface WireframePluginOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Output format
|
|
18
|
+
* - 'html': HTML/CSS rendering (inline styles)
|
|
19
|
+
* - 'html-preview': HTML with preview container (supports scaling)
|
|
20
|
+
* - 'svg': SVG image
|
|
21
|
+
* - 'svg-img': base64 encoded img tag
|
|
22
|
+
*/
|
|
23
|
+
format?: 'html' | 'html-preview' | 'svg' | 'svg-img';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Theme for rendering
|
|
27
|
+
* - 'light': Light theme
|
|
28
|
+
* - 'dark': Dark theme
|
|
29
|
+
*/
|
|
30
|
+
theme?: 'light' | 'dark';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Container class for wrapping SVG/HTML
|
|
34
|
+
*/
|
|
35
|
+
containerClass?: string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Error handling mode
|
|
39
|
+
* - 'code': Show original code
|
|
40
|
+
* - 'error': Show error message
|
|
41
|
+
* - 'both': Show both
|
|
42
|
+
*/
|
|
43
|
+
errorHandling?: 'code' | 'error' | 'both';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Container width for preview scaling (in pixels)
|
|
47
|
+
* When set, the wireframe will be scaled to fit this width
|
|
48
|
+
*/
|
|
49
|
+
containerWidth?: number;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Maximum scale factor (default: 1)
|
|
53
|
+
* Prevents the preview from being scaled up beyond this value
|
|
54
|
+
*/
|
|
55
|
+
maxScale?: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const defaultOptions: Required<WireframePluginOptions> = {
|
|
59
|
+
format: 'svg-img',
|
|
60
|
+
theme: 'light',
|
|
61
|
+
containerClass: 'wireframe-container',
|
|
62
|
+
errorHandling: 'both',
|
|
63
|
+
containerWidth: 0, // 0 means no scaling
|
|
64
|
+
maxScale: 1,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Render wireframe code to output format
|
|
69
|
+
*/
|
|
70
|
+
export function renderWireframe(
|
|
71
|
+
code: string,
|
|
72
|
+
options: WireframePluginOptions = {}
|
|
73
|
+
): string {
|
|
74
|
+
const opts = { ...defaultOptions, ...options };
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const doc = parse(code);
|
|
78
|
+
|
|
79
|
+
switch (opts.format) {
|
|
80
|
+
case 'html': {
|
|
81
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
82
|
+
return `
|
|
83
|
+
<div class="${opts.containerClass}">
|
|
84
|
+
<style>${css}</style>
|
|
85
|
+
${html}
|
|
86
|
+
</div>
|
|
87
|
+
`.trim();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case 'html-preview': {
|
|
91
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
92
|
+
const firstPage = doc.children[0];
|
|
93
|
+
const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);
|
|
94
|
+
|
|
95
|
+
const previewHtml = wrapInPreviewContainer(html, viewport, {
|
|
96
|
+
darkMode: opts.theme === 'dark',
|
|
97
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return `
|
|
101
|
+
<div class="${opts.containerClass}">
|
|
102
|
+
<style>${css}</style>
|
|
103
|
+
${previewHtml}
|
|
104
|
+
</div>
|
|
105
|
+
`.trim();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case 'svg': {
|
|
109
|
+
const { svg } = renderToSvg(doc);
|
|
110
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
case 'svg-img':
|
|
114
|
+
default: {
|
|
115
|
+
const { svg } = renderToSvg(doc);
|
|
116
|
+
// Use btoa for browser compatibility, Buffer for Node.js
|
|
117
|
+
const base64 =
|
|
118
|
+
typeof Buffer !== 'undefined'
|
|
119
|
+
? Buffer.from(svg).toString('base64')
|
|
120
|
+
: btoa(svg);
|
|
121
|
+
return `
|
|
122
|
+
<div class="${opts.containerClass}">
|
|
123
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
124
|
+
</div>
|
|
125
|
+
`.trim();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return renderError(code, error as Error, opts);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function renderError(
|
|
134
|
+
code: string,
|
|
135
|
+
error: Error,
|
|
136
|
+
options: Required<WireframePluginOptions>
|
|
137
|
+
): string {
|
|
138
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml(error.message)}</pre>`;
|
|
139
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml(code)}</code></pre>`;
|
|
140
|
+
|
|
141
|
+
switch (options.errorHandling) {
|
|
142
|
+
case 'code':
|
|
143
|
+
return codeHtml;
|
|
144
|
+
case 'error':
|
|
145
|
+
return errorHtml;
|
|
146
|
+
case 'both':
|
|
147
|
+
default:
|
|
148
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function escapeHtml(text: string): string {
|
|
153
|
+
return text
|
|
154
|
+
.replace(/&/g, '&')
|
|
155
|
+
.replace(/</g, '<')
|
|
156
|
+
.replace(/>/g, '>')
|
|
157
|
+
.replace(/"/g, '"')
|
|
158
|
+
.replace(/'/g, ''');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export { markdownItWireframe } from './markdown-it';
|
|
162
|
+
export { markedWireframe } from './marked';
|
|
163
|
+
export { remarkableWireframe } from './remarkable';
|