@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/README.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="logo.svg" width="128" height="128" alt="Wireweave Markdown">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@wireweave/markdown-plugin</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">Markdown plugins to embed Wireweave diagrams in your documentation</p>
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @wireweave/markdown-plugin
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @wireweave/markdown-plugin
|
|
15
|
+
# or
|
|
16
|
+
yarn add @wireweave/markdown-plugin
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Supported Libraries
|
|
20
|
+
|
|
21
|
+
- **markdown-it** - Most popular Markdown parser
|
|
22
|
+
- **marked** - Fast Markdown compiler
|
|
23
|
+
- **remarkable** - Markdown parser with CommonMark support
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### markdown-it
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import MarkdownIt from 'markdown-it';
|
|
31
|
+
import { markdownItWireframe } from '@wireweave/markdown-plugin';
|
|
32
|
+
|
|
33
|
+
const md = new MarkdownIt();
|
|
34
|
+
md.use(markdownItWireframe, {
|
|
35
|
+
format: 'svg-img', // or 'html', 'svg'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const html = md.render(`
|
|
39
|
+
# My Documentation
|
|
40
|
+
|
|
41
|
+
\`\`\`wireframe
|
|
42
|
+
page {
|
|
43
|
+
card p=4 {
|
|
44
|
+
title "Login"
|
|
45
|
+
input "Email" type=email
|
|
46
|
+
input "Password" type=password
|
|
47
|
+
button "Sign In" primary
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
\`\`\`
|
|
51
|
+
`);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### marked
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { marked } from 'marked';
|
|
58
|
+
import { markedWireframe } from '@wireweave/markdown-plugin';
|
|
59
|
+
|
|
60
|
+
marked.use(markedWireframe({
|
|
61
|
+
format: 'svg-img',
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
const html = marked.parse(`
|
|
65
|
+
# Documentation
|
|
66
|
+
|
|
67
|
+
\`\`\`wireframe
|
|
68
|
+
page { button "Click me" primary }
|
|
69
|
+
\`\`\`
|
|
70
|
+
`);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### remarkable
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { Remarkable } from 'remarkable';
|
|
77
|
+
import { remarkableWireframe } from '@wireweave/markdown-plugin';
|
|
78
|
+
|
|
79
|
+
const md = new Remarkable();
|
|
80
|
+
remarkableWireframe(md, {
|
|
81
|
+
format: 'svg-img',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const html = md.render(`
|
|
85
|
+
\`\`\`wireframe
|
|
86
|
+
page { card { text "Hello" } }
|
|
87
|
+
\`\`\`
|
|
88
|
+
`);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Options
|
|
92
|
+
|
|
93
|
+
All plugins accept the same options:
|
|
94
|
+
|
|
95
|
+
| Option | Type | Default | Description |
|
|
96
|
+
|--------|------|---------|-------------|
|
|
97
|
+
| `format` | `'html' \| 'svg' \| 'svg-img'` | `'svg-img'` | Output format |
|
|
98
|
+
| `containerClass` | `string` | `'wireframe-container'` | CSS class for wrapper div |
|
|
99
|
+
| `errorHandling` | `'code' \| 'error' \| 'both'` | `'both'` | How to handle parse errors |
|
|
100
|
+
|
|
101
|
+
### Output Formats
|
|
102
|
+
|
|
103
|
+
- **`svg-img`** (default): Base64-encoded SVG in an `<img>` tag. Best for compatibility.
|
|
104
|
+
- **`svg`**: Inline SVG. Allows CSS styling but may conflict with page styles.
|
|
105
|
+
- **`html`**: Full HTML/CSS rendering. Interactive but may conflict with page styles.
|
|
106
|
+
|
|
107
|
+
### Error Handling
|
|
108
|
+
|
|
109
|
+
- **`both`** (default): Shows both error message and original code
|
|
110
|
+
- **`error`**: Shows only the error message
|
|
111
|
+
- **`code`**: Shows only the original code
|
|
112
|
+
|
|
113
|
+
## Standalone Rendering
|
|
114
|
+
|
|
115
|
+
You can also use the `renderWireframe` function directly:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { renderWireframe } from '@wireweave/markdown-plugin';
|
|
119
|
+
|
|
120
|
+
const html = renderWireframe(`
|
|
121
|
+
page { button "Click" primary }
|
|
122
|
+
`, {
|
|
123
|
+
format: 'svg',
|
|
124
|
+
containerClass: 'my-wireframe',
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Styling
|
|
129
|
+
|
|
130
|
+
Add CSS to style the wireframe containers:
|
|
131
|
+
|
|
132
|
+
```css
|
|
133
|
+
.wireframe-container {
|
|
134
|
+
margin: 1rem 0;
|
|
135
|
+
border: 1px solid #e0e0e0;
|
|
136
|
+
border-radius: 4px;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.wireframe-container img {
|
|
141
|
+
display: block;
|
|
142
|
+
max-width: 100%;
|
|
143
|
+
height: auto;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.wireframe-error {
|
|
147
|
+
color: #d32f2f;
|
|
148
|
+
background: #ffebee;
|
|
149
|
+
padding: 1rem;
|
|
150
|
+
margin: 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.wireframe-source {
|
|
154
|
+
background: #f5f5f5;
|
|
155
|
+
padding: 1rem;
|
|
156
|
+
margin: 0;
|
|
157
|
+
overflow-x: auto;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Integration Examples
|
|
162
|
+
|
|
163
|
+
### VitePress / VuePress
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// .vitepress/config.ts
|
|
167
|
+
import { markdownItWireframe } from '@wireweave/markdown-plugin';
|
|
168
|
+
|
|
169
|
+
export default {
|
|
170
|
+
markdown: {
|
|
171
|
+
config: (md) => {
|
|
172
|
+
md.use(markdownItWireframe);
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Docusaurus
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
// docusaurus.config.js
|
|
182
|
+
const { markdownItWireframe } = require('@wireweave/markdown-plugin');
|
|
183
|
+
|
|
184
|
+
module.exports = {
|
|
185
|
+
presets: [
|
|
186
|
+
[
|
|
187
|
+
'@docusaurus/preset-classic',
|
|
188
|
+
{
|
|
189
|
+
docs: {
|
|
190
|
+
remarkPlugins: [],
|
|
191
|
+
rehypePlugins: [],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
],
|
|
196
|
+
// For markdown-it based setup
|
|
197
|
+
};
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Astro
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// astro.config.mjs
|
|
204
|
+
import { markdownItWireframe } from '@wireweave/markdown-plugin';
|
|
205
|
+
|
|
206
|
+
export default {
|
|
207
|
+
markdown: {
|
|
208
|
+
remarkPlugins: [],
|
|
209
|
+
rehypePlugins: [],
|
|
210
|
+
// For markdown-it integration
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## API Reference
|
|
216
|
+
|
|
217
|
+
### `markdownItWireframe(md, options?)`
|
|
218
|
+
|
|
219
|
+
Plugin for markdown-it.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import type MarkdownIt from 'markdown-it';
|
|
223
|
+
import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
|
|
224
|
+
|
|
225
|
+
function markdownItWireframe(
|
|
226
|
+
md: MarkdownIt,
|
|
227
|
+
options?: WireframePluginOptions
|
|
228
|
+
): void;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `markedWireframe(options?)`
|
|
232
|
+
|
|
233
|
+
Extension for marked.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import type { MarkedExtension } from 'marked';
|
|
237
|
+
import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
|
|
238
|
+
|
|
239
|
+
function markedWireframe(
|
|
240
|
+
options?: WireframePluginOptions
|
|
241
|
+
): MarkedExtension;
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `remarkableWireframe(md, options?)`
|
|
245
|
+
|
|
246
|
+
Plugin for remarkable.
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import type { Remarkable } from 'remarkable';
|
|
250
|
+
import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
|
|
251
|
+
|
|
252
|
+
function remarkableWireframe(
|
|
253
|
+
md: Remarkable,
|
|
254
|
+
options?: WireframePluginOptions
|
|
255
|
+
): void;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### `renderWireframe(code, options?)`
|
|
259
|
+
|
|
260
|
+
Standalone render function.
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
|
|
264
|
+
|
|
265
|
+
function renderWireframe(
|
|
266
|
+
code: string,
|
|
267
|
+
options?: WireframePluginOptions
|
|
268
|
+
): string;
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
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/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
markdownItWireframe: () => markdownItWireframe,
|
|
24
|
+
markedWireframe: () => markedWireframe,
|
|
25
|
+
remarkableWireframe: () => remarkableWireframe,
|
|
26
|
+
renderWireframe: () => renderWireframe
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(src_exports);
|
|
29
|
+
var import_core = require("@wireweave/core");
|
|
30
|
+
|
|
31
|
+
// src/markdown-it.ts
|
|
32
|
+
function markdownItWireframe(md, options = {}) {
|
|
33
|
+
const defaultFence = md.renderer.rules.fence;
|
|
34
|
+
md.renderer.rules.fence = (tokens, idx, opts, env, self) => {
|
|
35
|
+
const token = tokens[idx];
|
|
36
|
+
const info = token.info.trim();
|
|
37
|
+
if (info === "wireframe" || info === "wf") {
|
|
38
|
+
return renderWireframe(token.content, options);
|
|
39
|
+
}
|
|
40
|
+
if (defaultFence) {
|
|
41
|
+
return defaultFence(tokens, idx, opts, env, self);
|
|
42
|
+
}
|
|
43
|
+
return `<pre><code class="language-${info}">${md.utils.escapeHtml(token.content)}</code></pre>`;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/marked.ts
|
|
48
|
+
function markedWireframe(options = {}) {
|
|
49
|
+
return {
|
|
50
|
+
renderer: {
|
|
51
|
+
code(token) {
|
|
52
|
+
if (token.lang === "wireframe" || token.lang === "wf") {
|
|
53
|
+
return renderWireframe(token.text, options);
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/remarkable.ts
|
|
62
|
+
function escapeHtml(text) {
|
|
63
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
64
|
+
}
|
|
65
|
+
function remarkableWireframe(options = {}) {
|
|
66
|
+
return (md) => {
|
|
67
|
+
const rules = md.renderer.rules;
|
|
68
|
+
rules.fence = (tokens, idx, _opts, _env) => {
|
|
69
|
+
const token = tokens[idx];
|
|
70
|
+
const lang = token.params || "";
|
|
71
|
+
if (lang === "wireframe" || lang === "wf") {
|
|
72
|
+
return renderWireframe(token.content, options);
|
|
73
|
+
}
|
|
74
|
+
const langClass = lang ? ` class="language-${escapeHtml(lang)}"` : "";
|
|
75
|
+
return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>
|
|
76
|
+
`;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/index.ts
|
|
82
|
+
var defaultOptions = {
|
|
83
|
+
format: "svg-img",
|
|
84
|
+
theme: "light",
|
|
85
|
+
containerClass: "wireframe-container",
|
|
86
|
+
errorHandling: "both",
|
|
87
|
+
containerWidth: 0,
|
|
88
|
+
// 0 means no scaling
|
|
89
|
+
maxScale: 1
|
|
90
|
+
};
|
|
91
|
+
function renderWireframe(code, options = {}) {
|
|
92
|
+
const opts = { ...defaultOptions, ...options };
|
|
93
|
+
try {
|
|
94
|
+
const doc = (0, import_core.parse)(code);
|
|
95
|
+
switch (opts.format) {
|
|
96
|
+
case "html": {
|
|
97
|
+
const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
|
|
98
|
+
return `
|
|
99
|
+
<div class="${opts.containerClass}">
|
|
100
|
+
<style>${css}</style>
|
|
101
|
+
${html}
|
|
102
|
+
</div>
|
|
103
|
+
`.trim();
|
|
104
|
+
}
|
|
105
|
+
case "html-preview": {
|
|
106
|
+
const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
|
|
107
|
+
const firstPage = doc.children[0];
|
|
108
|
+
const viewport = (0, import_core.resolveViewport)(firstPage?.viewport, firstPage?.device);
|
|
109
|
+
const previewHtml = (0, import_core.wrapInPreviewContainer)(html, viewport, {
|
|
110
|
+
darkMode: opts.theme === "dark",
|
|
111
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
|
|
112
|
+
});
|
|
113
|
+
return `
|
|
114
|
+
<div class="${opts.containerClass}">
|
|
115
|
+
<style>${css}</style>
|
|
116
|
+
${previewHtml}
|
|
117
|
+
</div>
|
|
118
|
+
`.trim();
|
|
119
|
+
}
|
|
120
|
+
case "svg": {
|
|
121
|
+
const { svg } = (0, import_core.renderToSvg)(doc);
|
|
122
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
123
|
+
}
|
|
124
|
+
case "svg-img":
|
|
125
|
+
default: {
|
|
126
|
+
const { svg } = (0, import_core.renderToSvg)(doc);
|
|
127
|
+
const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
|
|
128
|
+
return `
|
|
129
|
+
<div class="${opts.containerClass}">
|
|
130
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
131
|
+
</div>
|
|
132
|
+
`.trim();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return renderError(code, error, opts);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function renderError(code, error, options) {
|
|
140
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml2(error.message)}</pre>`;
|
|
141
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml2(code)}</code></pre>`;
|
|
142
|
+
switch (options.errorHandling) {
|
|
143
|
+
case "code":
|
|
144
|
+
return codeHtml;
|
|
145
|
+
case "error":
|
|
146
|
+
return errorHtml;
|
|
147
|
+
case "both":
|
|
148
|
+
default:
|
|
149
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function escapeHtml2(text) {
|
|
153
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
154
|
+
}
|
|
155
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
156
|
+
0 && (module.exports = {
|
|
157
|
+
markdownItWireframe,
|
|
158
|
+
markedWireframe,
|
|
159
|
+
remarkableWireframe,
|
|
160
|
+
renderWireframe
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/markdown-it.ts","../src/marked.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 * markdown-it plugin for wireweave\n */\n\nimport type MarkdownIt from 'markdown-it';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * markdown-it plugin\n *\n * @example\n * ```typescript\n * import MarkdownIt from 'markdown-it';\n * import { markdownItWireframe } from '@wireweave/markdown-plugin/markdown-it';\n *\n * const md = new MarkdownIt();\n * md.use(markdownItWireframe, { format: 'svg' });\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markdownItWireframe(\n md: MarkdownIt,\n options: WireframePluginOptions = {}\n): void {\n const defaultFence = md.renderer.rules.fence;\n\n md.renderer.rules.fence = (tokens, idx, opts, env, self) => {\n const token = tokens[idx];\n const info = token.info.trim();\n\n if (info === 'wireframe' || info === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Use default renderer for other code blocks\n if (defaultFence) {\n return defaultFence(tokens, idx, opts, env, self);\n }\n\n return `<pre><code class=\"language-${info}\">${md.utils.escapeHtml(token.content)}</code></pre>`;\n };\n}\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","/**\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/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
parse,
|
|
4
|
+
render,
|
|
5
|
+
renderToSvg,
|
|
6
|
+
resolveViewport,
|
|
7
|
+
wrapInPreviewContainer
|
|
8
|
+
} from "@wireweave/core";
|
|
9
|
+
|
|
10
|
+
// src/markdown-it.ts
|
|
11
|
+
function markdownItWireframe(md, options = {}) {
|
|
12
|
+
const defaultFence = md.renderer.rules.fence;
|
|
13
|
+
md.renderer.rules.fence = (tokens, idx, opts, env, self) => {
|
|
14
|
+
const token = tokens[idx];
|
|
15
|
+
const info = token.info.trim();
|
|
16
|
+
if (info === "wireframe" || info === "wf") {
|
|
17
|
+
return renderWireframe(token.content, options);
|
|
18
|
+
}
|
|
19
|
+
if (defaultFence) {
|
|
20
|
+
return defaultFence(tokens, idx, opts, env, self);
|
|
21
|
+
}
|
|
22
|
+
return `<pre><code class="language-${info}">${md.utils.escapeHtml(token.content)}</code></pre>`;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/marked.ts
|
|
27
|
+
function markedWireframe(options = {}) {
|
|
28
|
+
return {
|
|
29
|
+
renderer: {
|
|
30
|
+
code(token) {
|
|
31
|
+
if (token.lang === "wireframe" || token.lang === "wf") {
|
|
32
|
+
return renderWireframe(token.text, options);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/remarkable.ts
|
|
41
|
+
function escapeHtml(text) {
|
|
42
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
43
|
+
}
|
|
44
|
+
function remarkableWireframe(options = {}) {
|
|
45
|
+
return (md) => {
|
|
46
|
+
const rules = md.renderer.rules;
|
|
47
|
+
rules.fence = (tokens, idx, _opts, _env) => {
|
|
48
|
+
const token = tokens[idx];
|
|
49
|
+
const lang = token.params || "";
|
|
50
|
+
if (lang === "wireframe" || lang === "wf") {
|
|
51
|
+
return renderWireframe(token.content, options);
|
|
52
|
+
}
|
|
53
|
+
const langClass = lang ? ` class="language-${escapeHtml(lang)}"` : "";
|
|
54
|
+
return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>
|
|
55
|
+
`;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/index.ts
|
|
61
|
+
var defaultOptions = {
|
|
62
|
+
format: "svg-img",
|
|
63
|
+
theme: "light",
|
|
64
|
+
containerClass: "wireframe-container",
|
|
65
|
+
errorHandling: "both",
|
|
66
|
+
containerWidth: 0,
|
|
67
|
+
// 0 means no scaling
|
|
68
|
+
maxScale: 1
|
|
69
|
+
};
|
|
70
|
+
function renderWireframe(code, options = {}) {
|
|
71
|
+
const opts = { ...defaultOptions, ...options };
|
|
72
|
+
try {
|
|
73
|
+
const doc = parse(code);
|
|
74
|
+
switch (opts.format) {
|
|
75
|
+
case "html": {
|
|
76
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
77
|
+
return `
|
|
78
|
+
<div class="${opts.containerClass}">
|
|
79
|
+
<style>${css}</style>
|
|
80
|
+
${html}
|
|
81
|
+
</div>
|
|
82
|
+
`.trim();
|
|
83
|
+
}
|
|
84
|
+
case "html-preview": {
|
|
85
|
+
const { html, css } = render(doc, { theme: opts.theme });
|
|
86
|
+
const firstPage = doc.children[0];
|
|
87
|
+
const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);
|
|
88
|
+
const previewHtml = wrapInPreviewContainer(html, viewport, {
|
|
89
|
+
darkMode: opts.theme === "dark",
|
|
90
|
+
containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
|
|
91
|
+
});
|
|
92
|
+
return `
|
|
93
|
+
<div class="${opts.containerClass}">
|
|
94
|
+
<style>${css}</style>
|
|
95
|
+
${previewHtml}
|
|
96
|
+
</div>
|
|
97
|
+
`.trim();
|
|
98
|
+
}
|
|
99
|
+
case "svg": {
|
|
100
|
+
const { svg } = renderToSvg(doc);
|
|
101
|
+
return `<div class="${opts.containerClass}">${svg}</div>`;
|
|
102
|
+
}
|
|
103
|
+
case "svg-img":
|
|
104
|
+
default: {
|
|
105
|
+
const { svg } = renderToSvg(doc);
|
|
106
|
+
const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
|
|
107
|
+
return `
|
|
108
|
+
<div class="${opts.containerClass}">
|
|
109
|
+
<img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
|
|
110
|
+
</div>
|
|
111
|
+
`.trim();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
return renderError(code, error, opts);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function renderError(code, error, options) {
|
|
119
|
+
const errorHtml = `<pre class="wireframe-error">${escapeHtml2(error.message)}</pre>`;
|
|
120
|
+
const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml2(code)}</code></pre>`;
|
|
121
|
+
switch (options.errorHandling) {
|
|
122
|
+
case "code":
|
|
123
|
+
return codeHtml;
|
|
124
|
+
case "error":
|
|
125
|
+
return errorHtml;
|
|
126
|
+
case "both":
|
|
127
|
+
default:
|
|
128
|
+
return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function escapeHtml2(text) {
|
|
132
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
markdownItWireframe,
|
|
136
|
+
markedWireframe,
|
|
137
|
+
remarkableWireframe,
|
|
138
|
+
renderWireframe
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/markdown-it.ts","../src/marked.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 * markdown-it plugin for wireweave\n */\n\nimport type MarkdownIt from 'markdown-it';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * markdown-it plugin\n *\n * @example\n * ```typescript\n * import MarkdownIt from 'markdown-it';\n * import { markdownItWireframe } from '@wireweave/markdown-plugin/markdown-it';\n *\n * const md = new MarkdownIt();\n * md.use(markdownItWireframe, { format: 'svg' });\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markdownItWireframe(\n md: MarkdownIt,\n options: WireframePluginOptions = {}\n): void {\n const defaultFence = md.renderer.rules.fence;\n\n md.renderer.rules.fence = (tokens, idx, opts, env, self) => {\n const token = tokens[idx];\n const info = token.info.trim();\n\n if (info === 'wireframe' || info === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Use default renderer for other code blocks\n if (defaultFence) {\n return defaultFence(tokens, idx, opts, env, self);\n }\n\n return `<pre><code class=\"language-${info}\">${md.utils.escapeHtml(token.content)}</code></pre>`;\n };\n}\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","/**\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"]}
|