ink-markdown-es 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 +95 -0
- package/dist/constants.d.ts +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +389 -0
- package/dist/utils.d.ts +4 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# ink-markdown-es
|
|
2
|
+
|
|
3
|
+
A modern performance markdown renderer for [ink](https://github.com/vadimdemedes/ink) using [marked](https://github.com/markedjs/marked).
|
|
4
|
+
|
|
5
|
+
Inspired by [ink-markdown](https://github.com/vadimdemedes/ink-markdown) and [prompt-kit](https://github.com/ibelick/prompt-kit).
|
|
6
|
+
|
|
7
|
+
Compare with [ink-markdown](https://github.com/vadimdemedes/ink-markdown):
|
|
8
|
+
|
|
9
|
+
- **ES module** support & only
|
|
10
|
+
- Use memo & useMemo to improve performance
|
|
11
|
+
- More flexible configuration (`renderers` prop)
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install ink-markdown-es # npm
|
|
17
|
+
|
|
18
|
+
pnpm add ink-markdown-es # pnpm
|
|
19
|
+
|
|
20
|
+
bun add ink-markdown-es # bun
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import Markdown from "ink-markdown-es";
|
|
25
|
+
import { render } from "ink";
|
|
26
|
+
|
|
27
|
+
const text = `# Hello World
|
|
28
|
+
|
|
29
|
+
This is a show case.
|
|
30
|
+
It's very fast!
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
- Render markdown in ink
|
|
34
|
+
- Support custom renderers
|
|
35
|
+
- **Bold text** and *italic text*
|
|
36
|
+
- Inline \`code\` support
|
|
37
|
+
|
|
38
|
+
### Code Block
|
|
39
|
+
|
|
40
|
+
\`\`\`javascript
|
|
41
|
+
const hello = "world";
|
|
42
|
+
console.log(hello);
|
|
43
|
+
\`\`\`
|
|
44
|
+
|
|
45
|
+
> This is a blockquote
|
|
46
|
+
> with multiple lines
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
Check out [this link](https://example.com) for more info.
|
|
51
|
+
|
|
52
|
+
1. First item
|
|
53
|
+
2. Second item
|
|
54
|
+
3. Third item
|
|
55
|
+
|
|
56
|
+
| Name | Age |
|
|
57
|
+
|------|-----|
|
|
58
|
+
| Alice | 25 |
|
|
59
|
+
| Bob | 30 |
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
render(
|
|
63
|
+
<Markdown
|
|
64
|
+
showSharp
|
|
65
|
+
renderers={{
|
|
66
|
+
h1: (text) => (
|
|
67
|
+
<Box padding={1} borderStyle="round" borderDimColor>
|
|
68
|
+
<Text bold color="greenBright">
|
|
69
|
+
{text}
|
|
70
|
+
</Text>
|
|
71
|
+
</Box>
|
|
72
|
+
),
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
{text}
|
|
76
|
+
</Markdown>
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
<img width="1919" height="689" alt="image" src="https://github.com/user-attachments/assets/d7cc741d-4c52-4b27-b183-ca8cce13007b" />
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
To install dependencies:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
bun install
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
To run:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bun run dev
|
|
95
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Token, type Tokens } from 'marked';
|
|
2
|
+
import type { MarkdownProps } from './types';
|
|
3
|
+
declare function MarkdownComponent({ children, styles, renderers, showSharp, }: MarkdownProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare const Markdown: import("react").MemoExoticComponent<typeof MarkdownComponent>;
|
|
5
|
+
export default Markdown;
|
|
6
|
+
export type { Token, Tokens };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { memo, useId, useMemo } from "react";
|
|
2
|
+
import { marked } from "marked";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
const DEFAULT_STYLES = {
|
|
5
|
+
h1: {
|
|
6
|
+
bold: true,
|
|
7
|
+
marginBottom: 1,
|
|
8
|
+
color: '#f74cc7ff'
|
|
9
|
+
},
|
|
10
|
+
h2: {
|
|
11
|
+
bold: true,
|
|
12
|
+
marginBottom: 1,
|
|
13
|
+
color: '#326cfcff'
|
|
14
|
+
},
|
|
15
|
+
h3: {
|
|
16
|
+
bold: true,
|
|
17
|
+
color: '#24ffedff'
|
|
18
|
+
},
|
|
19
|
+
h4: {
|
|
20
|
+
bold: true,
|
|
21
|
+
color: '#e29418ff'
|
|
22
|
+
},
|
|
23
|
+
h5: {
|
|
24
|
+
bold: true,
|
|
25
|
+
color: '#9fc214ff'
|
|
26
|
+
},
|
|
27
|
+
h6: {
|
|
28
|
+
bold: true,
|
|
29
|
+
dimColor: true,
|
|
30
|
+
color: '#88eb2bff'
|
|
31
|
+
},
|
|
32
|
+
paragraph: {},
|
|
33
|
+
blockquote: {
|
|
34
|
+
paddingLeft: 1,
|
|
35
|
+
dimColor: true,
|
|
36
|
+
borderTop: false,
|
|
37
|
+
borderBottom: false,
|
|
38
|
+
borderRight: false,
|
|
39
|
+
borderStyle: 'single',
|
|
40
|
+
borderDimColor: true
|
|
41
|
+
},
|
|
42
|
+
code: {
|
|
43
|
+
marginTop: 1
|
|
44
|
+
},
|
|
45
|
+
codespan: {
|
|
46
|
+
dimColor: true
|
|
47
|
+
},
|
|
48
|
+
list: {},
|
|
49
|
+
listItem: {
|
|
50
|
+
bullet: '●',
|
|
51
|
+
paddingLeft: 2
|
|
52
|
+
},
|
|
53
|
+
hr: {
|
|
54
|
+
char: '─',
|
|
55
|
+
width: 40,
|
|
56
|
+
dimColor: true
|
|
57
|
+
},
|
|
58
|
+
link: {
|
|
59
|
+
color: '#343afcff',
|
|
60
|
+
underline: true
|
|
61
|
+
},
|
|
62
|
+
strong: {
|
|
63
|
+
bold: true
|
|
64
|
+
},
|
|
65
|
+
em: {
|
|
66
|
+
italic: true
|
|
67
|
+
},
|
|
68
|
+
del: {
|
|
69
|
+
strikethrough: true,
|
|
70
|
+
dimColor: true
|
|
71
|
+
},
|
|
72
|
+
image: {
|
|
73
|
+
color: 'blue'
|
|
74
|
+
},
|
|
75
|
+
table: {},
|
|
76
|
+
tableCell: {
|
|
77
|
+
paddingRight: 2
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const TEXT_STYLE_KEYS = [
|
|
81
|
+
'color',
|
|
82
|
+
'backgroundColor',
|
|
83
|
+
'dimColor',
|
|
84
|
+
'bold',
|
|
85
|
+
'italic',
|
|
86
|
+
'underline',
|
|
87
|
+
'strikethrough',
|
|
88
|
+
'inverse',
|
|
89
|
+
'wrap'
|
|
90
|
+
];
|
|
91
|
+
const BOX_STYLE_KEYS = [
|
|
92
|
+
'paddingLeft',
|
|
93
|
+
'paddingRight',
|
|
94
|
+
'paddingTop',
|
|
95
|
+
'paddingBottom',
|
|
96
|
+
'padding',
|
|
97
|
+
'paddingX',
|
|
98
|
+
'paddingY',
|
|
99
|
+
'marginLeft',
|
|
100
|
+
'marginRight',
|
|
101
|
+
'marginTop',
|
|
102
|
+
'marginBottom',
|
|
103
|
+
'margin',
|
|
104
|
+
'marginX',
|
|
105
|
+
'marginY',
|
|
106
|
+
'borderStyle',
|
|
107
|
+
'borderColor',
|
|
108
|
+
'borderTop',
|
|
109
|
+
'borderBottom',
|
|
110
|
+
'borderLeft',
|
|
111
|
+
'borderRight',
|
|
112
|
+
'borderDimColor',
|
|
113
|
+
'borderTopColor',
|
|
114
|
+
'borderBottomColor',
|
|
115
|
+
'borderLeftColor',
|
|
116
|
+
'borderRightColor',
|
|
117
|
+
'borderTopDimColor',
|
|
118
|
+
'borderBottomDimColor',
|
|
119
|
+
'borderLeftDimColor',
|
|
120
|
+
'borderRightDimColor'
|
|
121
|
+
];
|
|
122
|
+
function extractTextProps(style) {
|
|
123
|
+
if (!style) return {};
|
|
124
|
+
const result = {};
|
|
125
|
+
for (const key of TEXT_STYLE_KEYS)if (key in style) result[key] = style[key];
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function extractBoxProps(style) {
|
|
129
|
+
if (!style) return {};
|
|
130
|
+
const result = {};
|
|
131
|
+
for (const key of BOX_STYLE_KEYS)if (key in style) result[key] = style[key];
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
function mergeStyles(defaultStyle, userStyle) {
|
|
135
|
+
if (!defaultStyle && !userStyle) return {};
|
|
136
|
+
if (!defaultStyle) return userStyle;
|
|
137
|
+
if (!userStyle) return defaultStyle;
|
|
138
|
+
return {
|
|
139
|
+
...defaultStyle,
|
|
140
|
+
...userStyle
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function renderInlineTokens(tokens, styles, renderers) {
|
|
144
|
+
if (!tokens || 0 === tokens.length) return null;
|
|
145
|
+
return tokens.map((token, index)=>{
|
|
146
|
+
const key = `inline-${index}`;
|
|
147
|
+
switch(token.type){
|
|
148
|
+
case 'text':
|
|
149
|
+
case 'escape':
|
|
150
|
+
{
|
|
151
|
+
const textToken = token;
|
|
152
|
+
if ('tokens' in textToken && textToken.tokens) return /*#__PURE__*/ React.createElement(Text, {
|
|
153
|
+
key: key
|
|
154
|
+
}, renderInlineTokens(textToken.tokens, styles, renderers));
|
|
155
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
156
|
+
key: key
|
|
157
|
+
}, textToken.text);
|
|
158
|
+
}
|
|
159
|
+
case 'strong':
|
|
160
|
+
{
|
|
161
|
+
const strongToken = token;
|
|
162
|
+
const strongStyle = mergeStyles(DEFAULT_STYLES.strong, styles.strong);
|
|
163
|
+
if (renderers.strong) return /*#__PURE__*/ React.createElement(Text, {
|
|
164
|
+
key: key
|
|
165
|
+
}, renderers.strong(renderInlineTokens(strongToken.tokens, styles, renderers), strongToken));
|
|
166
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
167
|
+
key: key,
|
|
168
|
+
...extractTextProps(strongStyle)
|
|
169
|
+
}, renderInlineTokens(strongToken.tokens, styles, renderers));
|
|
170
|
+
}
|
|
171
|
+
case 'em':
|
|
172
|
+
{
|
|
173
|
+
const emToken = token;
|
|
174
|
+
const emStyle = mergeStyles(DEFAULT_STYLES.em, styles.em);
|
|
175
|
+
if (renderers.em) return /*#__PURE__*/ React.createElement(Text, {
|
|
176
|
+
key: key
|
|
177
|
+
}, renderers.em(renderInlineTokens(emToken.tokens, styles, renderers), emToken));
|
|
178
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
179
|
+
key: key,
|
|
180
|
+
...extractTextProps(emStyle)
|
|
181
|
+
}, renderInlineTokens(emToken.tokens, styles, renderers));
|
|
182
|
+
}
|
|
183
|
+
case 'del':
|
|
184
|
+
{
|
|
185
|
+
const delToken = token;
|
|
186
|
+
const delStyle = mergeStyles(DEFAULT_STYLES.del, styles.del);
|
|
187
|
+
if (renderers.del) return /*#__PURE__*/ React.createElement(Text, {
|
|
188
|
+
key: key
|
|
189
|
+
}, renderers.del(renderInlineTokens(delToken.tokens, styles, renderers), delToken));
|
|
190
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
191
|
+
key: key,
|
|
192
|
+
...extractTextProps(delStyle)
|
|
193
|
+
}, renderInlineTokens(delToken.tokens, styles, renderers));
|
|
194
|
+
}
|
|
195
|
+
case 'codespan':
|
|
196
|
+
{
|
|
197
|
+
const codespanToken = token;
|
|
198
|
+
const codespanStyle = mergeStyles(DEFAULT_STYLES.codespan, styles.codespan);
|
|
199
|
+
if (renderers.codespan) return /*#__PURE__*/ React.createElement(Text, {
|
|
200
|
+
key: key
|
|
201
|
+
}, renderers.codespan(codespanToken.text, codespanToken));
|
|
202
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
203
|
+
key: key,
|
|
204
|
+
...extractTextProps(codespanStyle)
|
|
205
|
+
}, codespanToken.text);
|
|
206
|
+
}
|
|
207
|
+
case 'link':
|
|
208
|
+
{
|
|
209
|
+
const linkToken = token;
|
|
210
|
+
const linkStyle = mergeStyles(DEFAULT_STYLES.link, styles.link);
|
|
211
|
+
if (renderers.link) return /*#__PURE__*/ React.createElement(Text, {
|
|
212
|
+
key: key
|
|
213
|
+
}, renderers.link(linkToken.text, linkToken.href, linkToken.title, linkToken));
|
|
214
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
215
|
+
key: key,
|
|
216
|
+
...extractTextProps(linkStyle)
|
|
217
|
+
}, linkToken.text, linkToken.href && ` (${linkToken.href})`);
|
|
218
|
+
}
|
|
219
|
+
case 'image':
|
|
220
|
+
{
|
|
221
|
+
const imageToken = token;
|
|
222
|
+
const imageStyle = mergeStyles(DEFAULT_STYLES.image, styles.image);
|
|
223
|
+
if (renderers.image) return /*#__PURE__*/ React.createElement(Text, {
|
|
224
|
+
key: key
|
|
225
|
+
}, renderers.image(imageToken.text, imageToken.href, imageToken.title, imageToken));
|
|
226
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
227
|
+
key: key,
|
|
228
|
+
...extractTextProps(imageStyle)
|
|
229
|
+
}, "[Image: ", imageToken.text || imageToken.href, "]");
|
|
230
|
+
}
|
|
231
|
+
case 'br':
|
|
232
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
233
|
+
key: key
|
|
234
|
+
}, '\n');
|
|
235
|
+
default:
|
|
236
|
+
if ('text' in token) return /*#__PURE__*/ React.createElement(Text, {
|
|
237
|
+
key: key
|
|
238
|
+
}, token.text);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
function renderBlockToken(token, styles, renderers, showSharp) {
|
|
244
|
+
switch(token.type){
|
|
245
|
+
case 'heading':
|
|
246
|
+
{
|
|
247
|
+
const headingToken = token;
|
|
248
|
+
const headingKey = `h${headingToken.depth}`;
|
|
249
|
+
const styleKey = `h${headingToken.depth}`;
|
|
250
|
+
const renderer = renderers[headingKey];
|
|
251
|
+
if (renderer) return renderer(headingToken.text, headingToken);
|
|
252
|
+
const headingStyle = mergeStyles(DEFAULT_STYLES[styleKey], styles[styleKey]);
|
|
253
|
+
const mergedShowSharp = 'boolean' == typeof headingStyle.showSharp ? headingStyle.showSharp : Boolean(showSharp);
|
|
254
|
+
return /*#__PURE__*/ React.createElement(Box, extractBoxProps(headingStyle), /*#__PURE__*/ React.createElement(Text, extractTextProps(headingStyle), mergedShowSharp && `${'#'.repeat(headingToken.depth)} `, renderInlineTokens(headingToken.tokens, styles, renderers)));
|
|
255
|
+
}
|
|
256
|
+
case 'paragraph':
|
|
257
|
+
{
|
|
258
|
+
const paragraphToken = token;
|
|
259
|
+
const paragraphStyle = mergeStyles(DEFAULT_STYLES.paragraph, styles.paragraph);
|
|
260
|
+
const content = renderInlineTokens(paragraphToken.tokens, styles, renderers);
|
|
261
|
+
if (renderers.paragraph) return renderers.paragraph(content, paragraphToken);
|
|
262
|
+
return /*#__PURE__*/ React.createElement(Box, extractBoxProps(paragraphStyle), /*#__PURE__*/ React.createElement(Text, extractTextProps(paragraphStyle), content));
|
|
263
|
+
}
|
|
264
|
+
case 'code':
|
|
265
|
+
{
|
|
266
|
+
const codeToken = token;
|
|
267
|
+
const codeStyle = mergeStyles(DEFAULT_STYLES.code, styles.code);
|
|
268
|
+
if (renderers.code) return renderers.code(codeToken.text, codeToken.lang, codeToken);
|
|
269
|
+
return /*#__PURE__*/ React.createElement(Box, extractBoxProps(codeStyle), /*#__PURE__*/ React.createElement(Text, extractTextProps(codeStyle), codeToken.text));
|
|
270
|
+
}
|
|
271
|
+
case 'blockquote':
|
|
272
|
+
{
|
|
273
|
+
const blockquoteToken = token;
|
|
274
|
+
const blockquoteStyle = mergeStyles(DEFAULT_STYLES.blockquote, styles.blockquote);
|
|
275
|
+
const content = blockquoteToken.tokens.map((t, i)=>/*#__PURE__*/ React.createElement(Box, {
|
|
276
|
+
key: `bq-${i}`
|
|
277
|
+
}, renderBlockToken(t, styles, renderers)));
|
|
278
|
+
if (renderers.blockquote) return renderers.blockquote(/*#__PURE__*/ React.createElement(React.Fragment, null, content), blockquoteToken);
|
|
279
|
+
return /*#__PURE__*/ React.createElement(Box, extractBoxProps(blockquoteStyle), /*#__PURE__*/ React.createElement(Box, {
|
|
280
|
+
flexDirection: "column"
|
|
281
|
+
}, blockquoteToken.tokens.map((t, i)=>{
|
|
282
|
+
const rendered = renderBlockToken(t, styles, renderers);
|
|
283
|
+
if (rendered) return /*#__PURE__*/ React.createElement(Text, {
|
|
284
|
+
key: `bq-text-${i}`,
|
|
285
|
+
...extractTextProps(blockquoteStyle)
|
|
286
|
+
}, 'paragraph' === t.type ? renderInlineTokens(t.tokens, styles, renderers) : t.text || '');
|
|
287
|
+
return null;
|
|
288
|
+
})));
|
|
289
|
+
}
|
|
290
|
+
case 'list':
|
|
291
|
+
{
|
|
292
|
+
const listToken = token;
|
|
293
|
+
const listStyle = mergeStyles(DEFAULT_STYLES.list, styles.list);
|
|
294
|
+
const listItemStyle = mergeStyles(DEFAULT_STYLES.listItem, styles.listItem);
|
|
295
|
+
const bullet = listItemStyle.bullet || '●';
|
|
296
|
+
const items = listToken.items.map((item, index)=>{
|
|
297
|
+
const start = 'number' == typeof listToken.start ? listToken.start : 1;
|
|
298
|
+
const prefix = listToken.ordered ? `${start + index}. ` : `${bullet} `;
|
|
299
|
+
const itemContent = renderInlineTokens(item.tokens, styles, renderers);
|
|
300
|
+
if (renderers.listItem) return /*#__PURE__*/ React.createElement(Box, {
|
|
301
|
+
key: `li-${index}`,
|
|
302
|
+
...extractBoxProps(listItemStyle)
|
|
303
|
+
}, renderers.listItem(itemContent, item));
|
|
304
|
+
return /*#__PURE__*/ React.createElement(Box, {
|
|
305
|
+
key: `li-${index}`,
|
|
306
|
+
...extractBoxProps(listItemStyle)
|
|
307
|
+
}, /*#__PURE__*/ React.createElement(Text, extractTextProps(listItemStyle), prefix, itemContent));
|
|
308
|
+
});
|
|
309
|
+
if (renderers.list) return renderers.list(items, listToken.ordered, listToken);
|
|
310
|
+
return /*#__PURE__*/ React.createElement(Box, {
|
|
311
|
+
flexDirection: "column",
|
|
312
|
+
...extractBoxProps(listStyle)
|
|
313
|
+
}, items);
|
|
314
|
+
}
|
|
315
|
+
case 'hr':
|
|
316
|
+
{
|
|
317
|
+
const hrToken = token;
|
|
318
|
+
const hrStyle = mergeStyles(DEFAULT_STYLES.hr, styles.hr);
|
|
319
|
+
const char = hrStyle.char || '─';
|
|
320
|
+
const width = hrStyle.width || 40;
|
|
321
|
+
if (renderers.hr) return renderers.hr(hrToken);
|
|
322
|
+
return /*#__PURE__*/ React.createElement(Box, extractBoxProps(hrStyle), /*#__PURE__*/ React.createElement(Text, extractTextProps(hrStyle), char.repeat(width)));
|
|
323
|
+
}
|
|
324
|
+
case 'table':
|
|
325
|
+
{
|
|
326
|
+
const tableToken = token;
|
|
327
|
+
const tableStyle = mergeStyles(DEFAULT_STYLES.table, styles.table);
|
|
328
|
+
const cellStyle = mergeStyles(DEFAULT_STYLES.tableCell, styles.tableCell);
|
|
329
|
+
const headerCells = tableToken.header.map((cell, i)=>/*#__PURE__*/ React.createElement(Box, {
|
|
330
|
+
key: `th-${i}`,
|
|
331
|
+
...extractBoxProps(cellStyle)
|
|
332
|
+
}, /*#__PURE__*/ React.createElement(Text, {
|
|
333
|
+
bold: true,
|
|
334
|
+
...extractTextProps(cellStyle)
|
|
335
|
+
}, renderInlineTokens(cell.tokens, styles, renderers))));
|
|
336
|
+
const header = /*#__PURE__*/ React.createElement(Box, {
|
|
337
|
+
flexDirection: "row"
|
|
338
|
+
}, headerCells);
|
|
339
|
+
const bodyRows = tableToken.rows.map((row, rowIndex)=>/*#__PURE__*/ React.createElement(Box, {
|
|
340
|
+
key: `tr-${rowIndex}`,
|
|
341
|
+
flexDirection: "row"
|
|
342
|
+
}, row.map((cell, cellIndex)=>/*#__PURE__*/ React.createElement(Box, {
|
|
343
|
+
key: `td-${cellIndex}`,
|
|
344
|
+
...extractBoxProps(cellStyle)
|
|
345
|
+
}, /*#__PURE__*/ React.createElement(Text, extractTextProps(cellStyle), renderInlineTokens(cell.tokens, styles, renderers))))));
|
|
346
|
+
const body = /*#__PURE__*/ React.createElement(React.Fragment, null, bodyRows);
|
|
347
|
+
if (renderers.table) return renderers.table(header, body, tableToken);
|
|
348
|
+
return /*#__PURE__*/ React.createElement(Box, {
|
|
349
|
+
flexDirection: "column",
|
|
350
|
+
...extractBoxProps(tableStyle)
|
|
351
|
+
}, header, body);
|
|
352
|
+
}
|
|
353
|
+
case 'space':
|
|
354
|
+
return /*#__PURE__*/ React.createElement(Text, null, '\n');
|
|
355
|
+
case 'html':
|
|
356
|
+
{
|
|
357
|
+
const htmlToken = token;
|
|
358
|
+
return /*#__PURE__*/ React.createElement(Text, {
|
|
359
|
+
dimColor: true
|
|
360
|
+
}, htmlToken.text);
|
|
361
|
+
}
|
|
362
|
+
default:
|
|
363
|
+
if ('text' in token) return /*#__PURE__*/ React.createElement(Text, null, token.text);
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const src_MemoizedBlock = /*#__PURE__*/ memo(function({ token, styles, renderers, showSharp }) {
|
|
368
|
+
return /*#__PURE__*/ React.createElement(React.Fragment, null, renderBlockToken(token, styles, renderers, showSharp));
|
|
369
|
+
}, (prevProps, nextProps)=>prevProps.token === nextProps.token);
|
|
370
|
+
src_MemoizedBlock.displayName = 'MemoizedBlock';
|
|
371
|
+
function MarkdownComponent({ children, styles = {}, renderers = {}, showSharp = false }) {
|
|
372
|
+
const generatedId = useId();
|
|
373
|
+
const tokens = useMemo(()=>marked.lexer(children), [
|
|
374
|
+
children
|
|
375
|
+
]);
|
|
376
|
+
return /*#__PURE__*/ React.createElement(Box, {
|
|
377
|
+
flexDirection: "column"
|
|
378
|
+
}, tokens.map((token, index)=>/*#__PURE__*/ React.createElement(src_MemoizedBlock, {
|
|
379
|
+
key: `${generatedId}-block-${index}`,
|
|
380
|
+
token: token,
|
|
381
|
+
styles: styles,
|
|
382
|
+
renderers: renderers,
|
|
383
|
+
showSharp: showSharp
|
|
384
|
+
})));
|
|
385
|
+
}
|
|
386
|
+
const Markdown = /*#__PURE__*/ memo(MarkdownComponent);
|
|
387
|
+
Markdown.displayName = 'Markdown';
|
|
388
|
+
const src = Markdown;
|
|
389
|
+
export default src;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TextStyleProps, BoxStyleProps } from './types';
|
|
2
|
+
export declare function extractTextProps(style: (TextStyleProps & BoxStyleProps) | undefined): TextStyleProps;
|
|
3
|
+
export declare function extractBoxProps(style: (TextStyleProps & BoxStyleProps) | undefined): BoxStyleProps;
|
|
4
|
+
export declare function mergeStyles<T>(defaultStyle: T | undefined, userStyle: T | undefined): T;
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ink-markdown-es",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A modern performance markdown renderer for ink",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"markdown",
|
|
7
|
+
"ink",
|
|
8
|
+
"react",
|
|
9
|
+
"esm",
|
|
10
|
+
"terminal"
|
|
11
|
+
],
|
|
12
|
+
"author": "Mio <miownag@gmail.com>",
|
|
13
|
+
"repository": "https://github.com/miownag/ink-markdown-es",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"module": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"package.json",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rslib build",
|
|
31
|
+
"check": "biome check --write",
|
|
32
|
+
"dev": "bun --watch run examples/index.tsx",
|
|
33
|
+
"format": "biome format --write",
|
|
34
|
+
"prepublishOnly": "bun run build"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@rslib/core": "^0.19.2",
|
|
38
|
+
"@types/bun": "latest",
|
|
39
|
+
"@types/dedent": "^0.7.2",
|
|
40
|
+
"@types/react": "^19",
|
|
41
|
+
"@biomejs/biome": "2.3.8",
|
|
42
|
+
"ink": "^6",
|
|
43
|
+
"react": "^19",
|
|
44
|
+
"react-devtools-core": "^6",
|
|
45
|
+
"typescript": "^5.9.3"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"ink": "^6",
|
|
49
|
+
"react": "^19"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"dedent": "^1.7.1",
|
|
53
|
+
"marked": "^16.4.2"
|
|
54
|
+
}
|
|
55
|
+
}
|