ink-markdown-es 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -101
- package/dist/types.d.ts +0 -14
- package/package.json +5 -5
- package/README.md +0 -123
- package/dist/highlight.d.ts +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** biome-ignore-all lint/suspicious/noArrayIndexKey: <empty> */
|
|
2
2
|
import { type Token, type Tokens } from 'marked';
|
|
3
3
|
import type { MarkdownProps } from './types';
|
|
4
|
-
declare function MarkdownComponent({ children, id, styles, renderers, showSharp,
|
|
4
|
+
declare function MarkdownComponent({ children, id, styles, renderers, showSharp, }: MarkdownProps): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
declare const Markdown: import("react").MemoExoticComponent<typeof MarkdownComponent>;
|
|
6
6
|
export default Markdown;
|
|
7
7
|
export type { Token, Tokens };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { marked } from "marked";
|
|
4
|
-
import { memo,
|
|
5
|
-
import { codeToTokens } from "shiki";
|
|
4
|
+
import { memo, useId, useMemo } from "react";
|
|
6
5
|
const DEFAULT_STYLES = {
|
|
7
6
|
h1: {
|
|
8
7
|
bold: true,
|
|
@@ -42,7 +41,8 @@ const DEFAULT_STYLES = {
|
|
|
42
41
|
borderDimColor: true
|
|
43
42
|
},
|
|
44
43
|
code: {
|
|
45
|
-
marginTop: 1
|
|
44
|
+
marginTop: 1,
|
|
45
|
+
paddingX: 2
|
|
46
46
|
},
|
|
47
47
|
codespan: {
|
|
48
48
|
dimColor: true
|
|
@@ -121,35 +121,6 @@ const BOX_STYLE_KEYS = [
|
|
|
121
121
|
'borderLeftDimColor',
|
|
122
122
|
'borderRightDimColor'
|
|
123
123
|
];
|
|
124
|
-
async function highlightCodeAsync(code, language, theme = 'github-dark') {
|
|
125
|
-
try {
|
|
126
|
-
const result = await codeToTokens(code, {
|
|
127
|
-
lang: language || 'text',
|
|
128
|
-
theme: theme
|
|
129
|
-
});
|
|
130
|
-
const nodes = [];
|
|
131
|
-
let index = 0;
|
|
132
|
-
for(let lineIndex = 0; lineIndex < result.tokens.length; lineIndex++){
|
|
133
|
-
const line = result.tokens[lineIndex];
|
|
134
|
-
if (line) {
|
|
135
|
-
for (const token of line){
|
|
136
|
-
const color = token.color || void 0;
|
|
137
|
-
nodes.push(/*#__PURE__*/ jsx(Text, {
|
|
138
|
-
color: color,
|
|
139
|
-
children: token.content
|
|
140
|
-
}, `token-${index}`));
|
|
141
|
-
index++;
|
|
142
|
-
}
|
|
143
|
-
if (lineIndex < result.tokens.length - 1) nodes.push(/*#__PURE__*/ jsx(Text, {
|
|
144
|
-
children: '\n'
|
|
145
|
-
}, `nl-${lineIndex}`));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return nodes;
|
|
149
|
-
} catch {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
124
|
function extractTextProps(style) {
|
|
154
125
|
if (!style) return {};
|
|
155
126
|
const result = {};
|
|
@@ -171,51 +142,6 @@ function mergeStyles(defaultStyle, userStyle) {
|
|
|
171
142
|
...userStyle
|
|
172
143
|
};
|
|
173
144
|
}
|
|
174
|
-
function CodeBlock({ code, language, style, theme }) {
|
|
175
|
-
const [highlightedCode, setHighlightedCode] = useState(null);
|
|
176
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
177
|
-
useEffect(()=>{
|
|
178
|
-
let cancelled = false;
|
|
179
|
-
async function highlight() {
|
|
180
|
-
try {
|
|
181
|
-
const result = await highlightCodeAsync(code, language, theme);
|
|
182
|
-
if (!cancelled) {
|
|
183
|
-
setHighlightedCode(result);
|
|
184
|
-
setIsLoading(false);
|
|
185
|
-
}
|
|
186
|
-
} catch {
|
|
187
|
-
if (!cancelled) {
|
|
188
|
-
setHighlightedCode(null);
|
|
189
|
-
setIsLoading(false);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
highlight();
|
|
194
|
-
return ()=>{
|
|
195
|
-
cancelled = true;
|
|
196
|
-
};
|
|
197
|
-
}, [
|
|
198
|
-
code,
|
|
199
|
-
language,
|
|
200
|
-
theme
|
|
201
|
-
]);
|
|
202
|
-
if (isLoading || !highlightedCode) return /*#__PURE__*/ jsx(Box, {
|
|
203
|
-
...extractBoxProps(style),
|
|
204
|
-
children: /*#__PURE__*/ jsx(Text, {
|
|
205
|
-
...extractTextProps(style),
|
|
206
|
-
children: code
|
|
207
|
-
})
|
|
208
|
-
});
|
|
209
|
-
return /*#__PURE__*/ jsx(Box, {
|
|
210
|
-
paddingX: 2,
|
|
211
|
-
paddingY: 1,
|
|
212
|
-
...extractBoxProps(style),
|
|
213
|
-
children: /*#__PURE__*/ jsx(Text, {
|
|
214
|
-
...extractTextProps(style),
|
|
215
|
-
children: highlightedCode
|
|
216
|
-
})
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
145
|
function renderInlineTokens(tokens, styles, renderers) {
|
|
220
146
|
if (!tokens || 0 === tokens.length) return null;
|
|
221
147
|
return tokens.map((token, index)=>{
|
|
@@ -323,7 +249,7 @@ function renderInlineTokens(tokens, styles, renderers) {
|
|
|
323
249
|
}
|
|
324
250
|
});
|
|
325
251
|
}
|
|
326
|
-
function renderBlockToken(token, styles, renderers, showSharp
|
|
252
|
+
function renderBlockToken(token, styles, renderers, showSharp) {
|
|
327
253
|
switch(token.type){
|
|
328
254
|
case 'heading':
|
|
329
255
|
{
|
|
@@ -364,12 +290,6 @@ function renderBlockToken(token, styles, renderers, showSharp, highlight, theme
|
|
|
364
290
|
const codeToken = token;
|
|
365
291
|
const codeStyle = mergeStyles(DEFAULT_STYLES.code, styles.code);
|
|
366
292
|
if (renderers.code) return renderers.code(codeToken.text, codeToken.lang, codeToken);
|
|
367
|
-
if (highlight) return /*#__PURE__*/ jsx(CodeBlock, {
|
|
368
|
-
code: codeToken.text,
|
|
369
|
-
language: codeToken.lang,
|
|
370
|
-
style: codeStyle,
|
|
371
|
-
theme: theme
|
|
372
|
-
});
|
|
373
293
|
return /*#__PURE__*/ jsx(Box, {
|
|
374
294
|
...extractBoxProps(codeStyle),
|
|
375
295
|
children: /*#__PURE__*/ jsx(Text, {
|
|
@@ -382,22 +302,20 @@ function renderBlockToken(token, styles, renderers, showSharp, highlight, theme
|
|
|
382
302
|
{
|
|
383
303
|
const blockquoteToken = token;
|
|
384
304
|
const blockquoteStyle = mergeStyles(DEFAULT_STYLES.blockquote, styles.blockquote);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
305
|
+
if (renderers.blockquote) {
|
|
306
|
+
const content = blockquoteToken.tokens.map((t, i)=>/*#__PURE__*/ jsx(Box, {
|
|
307
|
+
children: renderBlockToken(t, styles, renderers, showSharp)
|
|
308
|
+
}, `bq-${i}`));
|
|
309
|
+
return renderers.blockquote(content, blockquoteToken);
|
|
310
|
+
}
|
|
389
311
|
return /*#__PURE__*/ jsx(Box, {
|
|
390
312
|
...extractBoxProps(blockquoteStyle),
|
|
391
313
|
children: /*#__PURE__*/ jsx(Box, {
|
|
392
314
|
flexDirection: "column",
|
|
393
|
-
children: blockquoteToken.tokens.map((t, i)
|
|
394
|
-
const rendered = renderBlockToken(t, styles, renderers, showSharp, highlight, theme);
|
|
395
|
-
if (rendered) return /*#__PURE__*/ jsx(Text, {
|
|
315
|
+
children: blockquoteToken.tokens.map((t, i)=>/*#__PURE__*/ jsx(Text, {
|
|
396
316
|
...extractTextProps(blockquoteStyle),
|
|
397
317
|
children: 'paragraph' === t.type ? renderInlineTokens(t.tokens, styles, renderers) : t.text || ''
|
|
398
|
-
}, `bq-text-${i}`)
|
|
399
|
-
return null;
|
|
400
|
-
})
|
|
318
|
+
}, `bq-text-${i}`))
|
|
401
319
|
})
|
|
402
320
|
});
|
|
403
321
|
}
|
|
@@ -495,7 +413,8 @@ function renderBlockToken(token, styles, renderers, showSharp, highlight, theme
|
|
|
495
413
|
/*#__PURE__*/ jsxs(Text, {
|
|
496
414
|
dimColor: true,
|
|
497
415
|
children: [
|
|
498
|
-
|
|
416
|
+
' ',
|
|
417
|
+
"│",
|
|
499
418
|
i < tableToken.header.length - 1 ? ' ' : ''
|
|
500
419
|
]
|
|
501
420
|
})
|
|
@@ -586,13 +505,13 @@ function renderBlockToken(token, styles, renderers, showSharp, highlight, theme
|
|
|
586
505
|
return null;
|
|
587
506
|
}
|
|
588
507
|
}
|
|
589
|
-
const src_MemoizedBlock = /*#__PURE__*/ memo(function({ token, styles, renderers, showSharp
|
|
508
|
+
const src_MemoizedBlock = /*#__PURE__*/ memo(function({ token, styles, renderers, showSharp }) {
|
|
590
509
|
return /*#__PURE__*/ jsx(Fragment, {
|
|
591
|
-
children: renderBlockToken(token, styles, renderers, showSharp
|
|
510
|
+
children: renderBlockToken(token, styles, renderers, showSharp)
|
|
592
511
|
});
|
|
593
512
|
}, (prevProps, nextProps)=>prevProps.token === nextProps.token);
|
|
594
513
|
src_MemoizedBlock.displayName = 'MemoizedBlock';
|
|
595
|
-
function MarkdownComponent({ children, id, styles = {}, renderers = {}, showSharp = false
|
|
514
|
+
function MarkdownComponent({ children, id, styles = {}, renderers = {}, showSharp = false }) {
|
|
596
515
|
const generatedId = useId();
|
|
597
516
|
const key = id || generatedId;
|
|
598
517
|
const tokens = useMemo(()=>marked.lexer(children, {
|
|
@@ -607,9 +526,7 @@ function MarkdownComponent({ children, id, styles = {}, renderers = {}, showShar
|
|
|
607
526
|
token: token,
|
|
608
527
|
styles: styles,
|
|
609
528
|
renderers: renderers,
|
|
610
|
-
showSharp: showSharp
|
|
611
|
-
highlight: highlight,
|
|
612
|
-
theme: theme
|
|
529
|
+
showSharp: showSharp
|
|
613
530
|
}, `${key}-block-${index}`))
|
|
614
531
|
});
|
|
615
532
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -62,24 +62,10 @@ export type MarkdownProps = {
|
|
|
62
62
|
styles?: BlockStyles;
|
|
63
63
|
renderers?: BlockRenderers;
|
|
64
64
|
showSharp?: boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Enable syntax highlighting for code blocks
|
|
67
|
-
* @default true
|
|
68
|
-
*/
|
|
69
|
-
highlight?: boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Shiki theme name for syntax highlighting
|
|
72
|
-
* @default 'github-dark'
|
|
73
|
-
* @example 'github-dark', 'github-light', 'nord', 'dracula', etc.
|
|
74
|
-
* @see https://shiki.style/themes
|
|
75
|
-
*/
|
|
76
|
-
theme?: string;
|
|
77
65
|
};
|
|
78
66
|
export type MemoizedBlockProps = {
|
|
79
67
|
token: Token;
|
|
80
68
|
styles: BlockStyles;
|
|
81
69
|
renderers: BlockRenderers;
|
|
82
70
|
showSharp: boolean;
|
|
83
|
-
highlight: boolean;
|
|
84
|
-
theme: string;
|
|
85
71
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ink-markdown-es",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A modern performance markdown renderer for ink",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
],
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "rslib build",
|
|
31
|
-
"check": "biome check --write",
|
|
31
|
+
"check": "biome check --write .",
|
|
32
32
|
"dev": "bun --watch run examples/index.tsx",
|
|
33
|
-
"format": "biome format --write",
|
|
33
|
+
"format": "biome format --write .",
|
|
34
34
|
"prepublishOnly": "bun run build"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@types/react": "^19",
|
|
41
41
|
"@biomejs/biome": "2.3.8",
|
|
42
42
|
"ink": "^6",
|
|
43
|
+
"ink-shiki-code": "workspace:*",
|
|
43
44
|
"react": "^19",
|
|
44
45
|
"react-devtools-core": "^6",
|
|
45
46
|
"typescript": "^5.9.3",
|
|
@@ -51,7 +52,6 @@
|
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
54
|
"dedent": "^1.7.1",
|
|
54
|
-
"marked": "^16.4.2"
|
|
55
|
-
"shiki": "^3.22.0"
|
|
55
|
+
"marked": "^16.4.2"
|
|
56
56
|
}
|
|
57
57
|
}
|
package/README.md
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
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
|
-
const text = `# Hello World
|
|
25
|
-
|
|
26
|
-
This is a show case.
|
|
27
|
-
It's very fast!
|
|
28
|
-
|
|
29
|
-
## Features
|
|
30
|
-
- Render markdown in ink
|
|
31
|
-
- Support custom renderers
|
|
32
|
-
- **Bold text** and *italic text*
|
|
33
|
-
- Inline \`code\` support
|
|
34
|
-
- **Syntax highlighting** for code blocks powered by highlight.js
|
|
35
|
-
|
|
36
|
-
### Code Block with Syntax Highlighting
|
|
37
|
-
|
|
38
|
-
\`\`\`typescript
|
|
39
|
-
interface User {
|
|
40
|
-
id: number;
|
|
41
|
-
name: string;
|
|
42
|
-
email: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const user: User = {
|
|
46
|
-
id: 1,
|
|
47
|
-
name: "Alice",
|
|
48
|
-
email: "alice@example.com"
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
async function fetchUser(id: number): Promise<User> {
|
|
52
|
-
const response = await fetch(\`/api/users/\${id}\`);
|
|
53
|
-
return response.json();
|
|
54
|
-
}
|
|
55
|
-
\`\`\`
|
|
56
|
-
|
|
57
|
-
> This is a blockquote
|
|
58
|
-
> with multiple lines
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
Check out [this link](https://example.com) for more info.
|
|
63
|
-
|
|
64
|
-
1. First item
|
|
65
|
-
2. Second item
|
|
66
|
-
3. Third item
|
|
67
|
-
|
|
68
|
-
| Name | Age |
|
|
69
|
-
|------|-----|
|
|
70
|
-
| Alice | 25 |
|
|
71
|
-
| Bob | 30 |
|
|
72
|
-
`;
|
|
73
|
-
|
|
74
|
-
const TestApp = () => {
|
|
75
|
-
useInput(() => {});
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<Markdown
|
|
79
|
-
showSharp
|
|
80
|
-
theme="dracula"
|
|
81
|
-
renderers={{
|
|
82
|
-
h1: (text) => (
|
|
83
|
-
<Box padding={1} borderStyle="round" borderDimColor>
|
|
84
|
-
<Text bold color="greenBright">
|
|
85
|
-
{text}
|
|
86
|
-
</Text>
|
|
87
|
-
</Box>
|
|
88
|
-
),
|
|
89
|
-
}}
|
|
90
|
-
>
|
|
91
|
-
{text}
|
|
92
|
-
</Markdown>
|
|
93
|
-
);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
render(<TestApp />);
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
<img width="1904" height="964" alt="image" src="https://github.com/user-attachments/assets/bed0c942-6d08-4f24-a42a-4999bdf1fc85" />
|
|
101
|
-
|
|
102
|
-
## Props
|
|
103
|
-
|
|
104
|
-
- `children` (string): The markdown content to render.
|
|
105
|
-
- `id` (string, optional): A unique identifier for the component. In AI scene, it's useful to identify the component in the DOM tree, you can use AI message id.
|
|
106
|
-
- `styles` (BlockStyles, optional): Custom styles for markdown blocks.
|
|
107
|
-
- `renderers` (BlockRenderers, optional): Custom renderers for markdown blocks.
|
|
108
|
-
- `showSharp` (boolean, optional): Whether to show sharp signs for headings. Default is `false`.
|
|
109
|
-
- `theme` (string, optional): The theme for syntax highlighting. Default is `github-dark`. Check out [shiki](https://shiki.style/themes) for more themes.
|
|
110
|
-
|
|
111
|
-
## Contributing
|
|
112
|
-
|
|
113
|
-
To install dependencies:
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
bun install
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
To run:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
bun run dev
|
|
123
|
-
```
|
package/dist/highlight.d.ts
DELETED