svelte-streamdown 2.0.0 → 2.0.1
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 +16 -8
- package/dist/Block.svelte +1 -21
- package/dist/Elements/Code.svelte +5 -3
- package/dist/marked/index.d.ts +1 -1
- package/dist/marked/index.js +0 -3
- package/dist/marked/marked-alert.js +5 -6
- package/dist/marked/marked-footnotes.js +1 -1
- package/dist/marked/marked-table.d.ts +9 -2
- package/dist/theme.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,14 +45,21 @@ Perfect for AI-powered applications that need to stream and render markdown cont
|
|
|
45
45
|
|
|
46
46
|
Beautiful, responsive typography with **built-in Tailwind CSS classes** for headings, lists, code blocks, and more. Comes with a complete default theme that works out of the box.
|
|
47
47
|
|
|
48
|
-
### 📝
|
|
49
|
-
|
|
50
|
-
Full support for
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
48
|
+
### 📝 Extensive Markdown Features
|
|
49
|
+
|
|
50
|
+
Full support for
|
|
51
|
+
- Basic text marks: **bold**, *italic*, `code`, ~~Strikethrough~~
|
|
52
|
+
- ~Subscript~ and ^Superscript^
|
|
53
|
+
- [Links](https://svelte-streamdown.beynar.workers.dev/)
|
|
54
|
+
- Headings (H1–H6)
|
|
55
|
+
- Blockquotes
|
|
56
|
+
- Github alert
|
|
57
|
+
- Ordered & unordered lists (including roman, alpha, nested)
|
|
58
|
+
- Task lists ([ ] and [x])
|
|
59
|
+
- Code blocks
|
|
60
|
+
- Mermaid diagrams
|
|
61
|
+
- Math $expressions$
|
|
62
|
+
- Complex tables
|
|
56
63
|
- Footnotes [^1]
|
|
57
64
|
|
|
58
65
|
[^1]:
|
|
@@ -243,6 +250,7 @@ This Svelte port maintains feature parity with the original [Streamdown](https:/
|
|
|
243
250
|
> [!NOTE]
|
|
244
251
|
> Streamdown comes with **built-in Tailwind CSS classes** for beautiful default styling. To ensure all styles are included in your build, add the following to your `app.css` or main CSS file:
|
|
245
252
|
> This setup is primarily necessary if you're using Tailwind CSS v4's new `@source` directive or if you have aggressive purging enabled in older versions. If you're using standard Tailwind CSS v3+ with default purging, Streamdown's styles should be automatically included when the component is imported and used in your application.
|
|
253
|
+
>
|
|
246
254
|
> This ensures that all Streamdown's default styling is included in your Tailwind build process.
|
|
247
255
|
|
|
248
256
|
```css
|
package/dist/Block.svelte
CHANGED
|
@@ -13,32 +13,12 @@
|
|
|
13
13
|
} = $props();
|
|
14
14
|
|
|
15
15
|
const tokens = $derived(lex(parseIncompleteMarkdown(block.trim())));
|
|
16
|
-
|
|
17
|
-
const getChildren = (token: StreamdownToken) => {
|
|
18
|
-
if (!token) {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
const children =
|
|
22
|
-
'tokens' in token ? ((token.tokens || []) as StreamdownToken[]) : ([] as StreamdownToken[]);
|
|
23
|
-
|
|
24
|
-
if (!children.length && token.type !== 'text') {
|
|
25
|
-
return [
|
|
26
|
-
{
|
|
27
|
-
type: 'text',
|
|
28
|
-
text: 'text' in token ? token.text : '',
|
|
29
|
-
raw: 'raw' in token ? token.raw : '',
|
|
30
|
-
tokens: []
|
|
31
|
-
}
|
|
32
|
-
] satisfies StreamdownToken[];
|
|
33
|
-
}
|
|
34
|
-
return children;
|
|
35
|
-
};
|
|
36
16
|
</script>
|
|
37
17
|
|
|
38
18
|
{#snippet renderChildren(tokens: StreamdownToken[])}
|
|
39
19
|
{#each tokens as token}
|
|
40
20
|
{#if token}
|
|
41
|
-
{@const children =
|
|
21
|
+
{@const children = (token as any)?.tokens || []}
|
|
42
22
|
{@const isTextOnlyNode = children.length === 0}
|
|
43
23
|
<Element {token}>
|
|
44
24
|
{#if isTextOnlyNode}
|
|
@@ -65,7 +65,10 @@
|
|
|
65
65
|
</div>
|
|
66
66
|
<div style="height: fit-content; width: 100%;" class={streamdown.theme.code.container}>
|
|
67
67
|
<div>
|
|
68
|
+
<!-- {@render Skeleton()} -->
|
|
68
69
|
{#if highlighter.isReady(theme, language as any)}
|
|
70
|
+
<!-- {@render Skeleton()} -->
|
|
71
|
+
|
|
69
72
|
{@const code = highlighter.highlightCode(
|
|
70
73
|
codeContent,
|
|
71
74
|
language as any,
|
|
@@ -80,16 +83,15 @@
|
|
|
80
83
|
</div>
|
|
81
84
|
</div>
|
|
82
85
|
|
|
83
|
-
<!-- Need to improve this -->
|
|
84
86
|
{#snippet Skeleton()}
|
|
85
|
-
{@const lines =
|
|
87
|
+
{@const lines = token.text.split('\n')}
|
|
86
88
|
<!-- -->
|
|
87
89
|
|
|
88
90
|
<!-- --><code
|
|
89
91
|
class={streamdown.theme.code.pre}
|
|
90
92
|
style="height: fit-content; width: 100%; display: flex; flex-direction: column;"
|
|
91
93
|
><!-- -->{#each lines as line}<!-- --><span class={streamdown.theme.code.skeleton}
|
|
92
|
-
>{line}</span
|
|
94
|
+
>{line.trim().length > 0 ? line : '\u200B'}</span
|
|
93
95
|
><!-- -->
|
|
94
96
|
<!-- -->{/each}<!-- --></code
|
|
95
97
|
><!-- -->
|
package/dist/marked/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { type MathToken } from './marked-math.js';
|
|
|
5
5
|
import { type SubSupToken } from './marked-subsup.js';
|
|
6
6
|
import { type ListItemToken, type ListToken } from './marked-list.js';
|
|
7
7
|
import { type TableToken, type THead, type TBody, type TFoot, type THeadRow, type TRow, type TH, type TD } from './marked-table.js';
|
|
8
|
-
export type StreamdownToken = Exclude<MarkedToken, Tokens.List | Tokens.ListItem
|
|
8
|
+
export type StreamdownToken = Exclude<MarkedToken, Tokens.List | Tokens.ListItem> | ListToken | ListItemToken | MathToken | AlertToken | FootnoteToken | SubSupToken | TableToken | THead | TBody | TFoot | THeadRow | TRow | TH | TD;
|
|
9
9
|
export type { TableToken, THead, TBody, TFoot, THeadRow, TRow, TH, TD } from './marked-table.js';
|
|
10
10
|
export declare const lex: (markdown: string) => StreamdownToken[];
|
|
11
11
|
export declare const parseBlocks: (markdown: string) => string[];
|
package/dist/marked/index.js
CHANGED
|
@@ -6,8 +6,6 @@ import markedSubSup, {} from './marked-subsup.js';
|
|
|
6
6
|
import { markedList } from './marked-list.js';
|
|
7
7
|
import { markedTable } from './marked-table.js';
|
|
8
8
|
const completeLexer = new Marked({
|
|
9
|
-
// Enable GFM features but disable built-in tables
|
|
10
|
-
gfm: true,
|
|
11
9
|
tokenizer: {
|
|
12
10
|
table: () => {
|
|
13
11
|
return false;
|
|
@@ -21,7 +19,6 @@ const completeLexer = new Marked({
|
|
|
21
19
|
.use(markedList())
|
|
22
20
|
.use(markedTable());
|
|
23
21
|
const blockLexer = new Lexer({
|
|
24
|
-
gfm: true,
|
|
25
22
|
extensions: {
|
|
26
23
|
childTokens: {},
|
|
27
24
|
renderers: {},
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { Lexer } from 'marked';
|
|
2
2
|
const variants = ['note', 'tip', 'important', 'warning', 'caution'];
|
|
3
|
-
// export function createSyntaxPattern(type: variantType): string {
|
|
4
|
-
// return `^(?:\\[!${type.toUpperCase()}])\\s*?\n*`;
|
|
5
|
-
// }
|
|
6
3
|
export function createSyntaxPattern(type) {
|
|
7
4
|
return `^\\s*\\[!${type.toUpperCase()}\\]\\s+`;
|
|
8
5
|
}
|
|
@@ -14,7 +11,7 @@ export default function markedAlert() {
|
|
|
14
11
|
{
|
|
15
12
|
name: 'alert',
|
|
16
13
|
level: 'block',
|
|
17
|
-
tokenizer(src
|
|
14
|
+
tokenizer(src) {
|
|
18
15
|
const cap = defaultTokenizer.rules.block.blockquote.exec(src);
|
|
19
16
|
if (cap) {
|
|
20
17
|
const blockquoteToken = defaultTokenizer.blockquote(src);
|
|
@@ -30,9 +27,11 @@ export function processAlertToken(token, tokenizer) {
|
|
|
30
27
|
const matchedVariant = variants.find((type) => new RegExp(createSyntaxPattern(type)).test(('text' in token && token.text) || ''));
|
|
31
28
|
if (!matchedVariant)
|
|
32
29
|
return;
|
|
33
|
-
const tokens = token.tokens
|
|
30
|
+
const tokens = token.tokens
|
|
31
|
+
.map((token) => {
|
|
34
32
|
return tokenizer.lexer.blockTokens(token.raw.replaceAll(`[!${matchedVariant.toUpperCase()}]`, '').trim(), [])[0];
|
|
35
|
-
})
|
|
33
|
+
})
|
|
34
|
+
.filter(Boolean);
|
|
36
35
|
Object.assign(token, {
|
|
37
36
|
type: 'alert',
|
|
38
37
|
variant: matchedVariant,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TokenizerExtensionFunction } from 'marked';
|
|
2
2
|
export interface SpanTableOptions {
|
|
3
3
|
useTheadTbody?: boolean;
|
|
4
4
|
useTfoot?: boolean;
|
|
@@ -55,5 +55,12 @@ type WorkingRow = WorkingCell[];
|
|
|
55
55
|
export declare const DEFAULT_OPTIONS: Required<SpanTableOptions>;
|
|
56
56
|
export declare const getTableCell: (text: string, cell: BaseCell, type: "th" | "td", align: string | null) => string;
|
|
57
57
|
export declare const splitCells: (tableRow: string, count: number | null, prevRow?: WorkingRow | null, maxColspan?: number | null) => WorkingRow;
|
|
58
|
-
export declare function markedTable(options?: SpanTableOptions):
|
|
58
|
+
export declare function markedTable(options?: SpanTableOptions): {
|
|
59
|
+
extensions: {
|
|
60
|
+
name: string;
|
|
61
|
+
level: 'block' | 'inline';
|
|
62
|
+
start: (src: string) => number | undefined;
|
|
63
|
+
tokenizer: TokenizerExtensionFunction;
|
|
64
|
+
}[];
|
|
65
|
+
};
|
|
59
66
|
export {};
|
package/dist/theme.js
CHANGED
|
@@ -35,7 +35,7 @@ export const theme = {
|
|
|
35
35
|
},
|
|
36
36
|
li: {
|
|
37
37
|
base: 'py-1 marker:hidden',
|
|
38
|
-
checkbox: '-
|
|
38
|
+
checkbox: ' mr-2'
|
|
39
39
|
},
|
|
40
40
|
code: {
|
|
41
41
|
base: 'my-4 w-full overflow-hidden rounded-xl border border-gray-200 flex flex-col',
|
|
@@ -43,7 +43,7 @@ export const theme = {
|
|
|
43
43
|
header: 'flex items-center justify-between bg-gray-100/80 p-2 pb-0 text-gray-600 text-xs',
|
|
44
44
|
button: 'cursor-pointer size-6 p-1 text-gray-600 transition-all hover:text-gray-900 rounded hover:bg-gray-100',
|
|
45
45
|
language: 'ml-1 font-mono lowercase',
|
|
46
|
-
skeleton: 'rounded-md font-mono text-transparent bg-gray-200 whitespace-nowrap inline-block',
|
|
46
|
+
skeleton: 'rounded-md font-mono text-transparent bg-gray-200 scale-y-90 animate-pulse whitespace-nowrap inline-block',
|
|
47
47
|
pre: 'overflow-x-auto font-mono p-0 bg-gray-100/40'
|
|
48
48
|
},
|
|
49
49
|
codespan: {
|
|
@@ -162,7 +162,7 @@ export const shadcnTheme = {
|
|
|
162
162
|
},
|
|
163
163
|
li: {
|
|
164
164
|
base: 'py-1',
|
|
165
|
-
checkbox: '-
|
|
165
|
+
checkbox: ' mr-2'
|
|
166
166
|
},
|
|
167
167
|
code: {
|
|
168
168
|
base: 'my-4 w-full overflow-hidden rounded-lg border border-border flex flex-col',
|
|
@@ -170,7 +170,7 @@ export const shadcnTheme = {
|
|
|
170
170
|
header: 'flex items-center justify-between bg-muted/80 p-2 pb-0 text-muted-foreground text-xs',
|
|
171
171
|
button: 'cursor-pointer size-6 p-1 text-muted-foreground transition-all hover:text-foreground rounded hover:bg-muted',
|
|
172
172
|
language: 'ml-1 font-mono lowercase',
|
|
173
|
-
skeleton: 'rounded-md font-mono text-transparent bg-
|
|
173
|
+
skeleton: 'rounded-md font-mono text-transparent bg-border/80 scale-y-90 w-fit animate-pulse whitespace-nowrap inline-block',
|
|
174
174
|
pre: 'overflow-x-auto font-mono p-0 bg-muted/40'
|
|
175
175
|
},
|
|
176
176
|
codespan: {
|