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 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
- ### 📝 GitHub Flavored Markdown
49
-
50
- Full support for GitHub Flavored Markdown including:
51
-
52
- - Tables
53
- - ~~Strikethrough~~
54
- - Subscript (H~2~O)
55
- - Superscript (E = mc^2^)
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 = getChildren(token)}
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 = codeContent.split('\n')}
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
  ><!-- -->
@@ -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 | Tokens.Table> | ListToken | ListItemToken | MathToken | AlertToken | FootnoteToken | SubSupToken | TableToken | THead | TBody | TFoot | THeadRow | TRow | TH | TD;
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[];
@@ -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, tokens) {
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.map((token) => {
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 { lex } from './index.js';
1
+ import {} from './index.js';
2
2
  import { StreamdownContext } from '../Streamdown.js';
3
3
  import { getContext } from 'svelte';
4
4
  const safeGetContext = () => {
@@ -1,4 +1,4 @@
1
- import type { MarkedExtension } from 'marked';
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): MarkedExtension;
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: '-ml-2'
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: '-ml-2'
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-muted whitespace-nowrap inline-block',
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: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-streamdown",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",