svelte-streamdown 2.2.0 → 2.2.2

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.
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { useStreamdown } from './streamdown.svelte.js';
3
-
4
3
  let { text }: { text: string } = $props();
5
4
 
6
5
  const streamdown = useStreamdown();
@@ -17,10 +16,7 @@
17
16
 
18
17
  return text.split(splitRegex).filter((token) => token.length > 0);
19
18
  };
20
-
21
- let tokens = $derived.by(() => {
22
- return tokenizeNewContent(text);
23
- });
19
+ const tokens = $derived(tokenizeNewContent(text));
24
20
 
25
21
  const isMounted = streamdown.isMounted;
26
22
  </script>
package/dist/Block.svelte CHANGED
@@ -7,9 +7,11 @@
7
7
  import AnimatedBlock from './AnimatedBlock.svelte';
8
8
 
9
9
  let {
10
- block
10
+ block,
11
+ insideFootnote = false
11
12
  }: {
12
13
  block: string;
14
+ insideFootnote?: boolean;
13
15
  } = $props();
14
16
  const id = $props.id();
15
17
  const tokens = $derived(lex(parseIncompleteMarkdown(block.trim())));
@@ -23,7 +25,7 @@
23
25
  {@const isTextOnlyNode = children.length === 0}
24
26
  <Element {token}>
25
27
  {#if isTextOnlyNode}
26
- {#if streamdown.animation.enabled}
28
+ {#if streamdown.animation.enabled && !insideFootnote}
27
29
  <AnimatedText text={'text' in token ? token.text : ''} />
28
30
  {:else}
29
31
  {'text' in token ? token.text : ''}
@@ -36,7 +38,7 @@
36
38
  {/each}
37
39
  {/snippet}
38
40
 
39
- {#if streamdown.animation.enabled}
41
+ {#if streamdown.animation.enabled && !insideFootnote}
40
42
  <AnimatedBlock>
41
43
  {@render renderChildren(tokens)}
42
44
  </AnimatedBlock>
@@ -1,5 +1,6 @@
1
1
  type $$ComponentProps = {
2
2
  block: string;
3
+ insideFootnote?: boolean;
3
4
  };
4
5
  declare const Block: import("svelte").Component<$$ComponentProps, {}, "">;
5
6
  type Block = ReturnType<typeof Block>;
@@ -12,6 +12,8 @@
12
12
  import FootnoteRef from './FootnoteRef.svelte';
13
13
  let { token, children }: { token: StreamdownToken; children: Snippet } = $props();
14
14
  const streamdown = useStreamdown();
15
+
16
+ const isMounted = streamdown.isMounted;
15
17
  </script>
16
18
 
17
19
  {#if token.type === 'heading'}
@@ -91,6 +93,7 @@
91
93
  {:else if token.type === 'list_item'}
92
94
  <Slot props={{ children, token }} render={streamdown.snippets.li}>
93
95
  <li
96
+ style={isMounted ? streamdown.animationBlockStyle : undefined}
94
97
  style:list-style-type={token.task ? 'none' : undefined}
95
98
  {...token.value && !token.task ? { value: token.value } : {}}
96
99
  class={streamdown.theme.li.base}
@@ -100,7 +100,7 @@
100
100
  class={`${streamdown.theme.footnotePopover.base}`}
101
101
  >
102
102
  {#each token.content.lines as line}
103
- <Block block={line} />
103
+ <Block insideFootnote block={line} />
104
104
  {/each}
105
105
  </dialog>
106
106
  </Slot>
@@ -1,33 +1,56 @@
1
- import { Lexer, Marked } from 'marked';
1
+ import { Lexer } from 'marked';
2
2
  import markedAlert, {} from './marked-alert.js';
3
3
  import markedFootnote, {} from './marked-footnotes.js';
4
4
  import { markedMath } from './marked-math.js';
5
5
  import markedSubSup, {} from './marked-subsup.js';
6
6
  import { markedList } from './marked-list.js';
7
7
  import { markedTable } from './marked-table.js';
8
- const completeLexer = new Marked({
9
- tokenizer: {
10
- table: () => {
11
- return false;
8
+ const extensions = [
9
+ markedTable(),
10
+ markedFootnote(),
11
+ markedAlert(),
12
+ markedMath(),
13
+ markedSubSup(),
14
+ markedList()
15
+ ];
16
+ const parseExtensions = (...ext) => {
17
+ const options = {
18
+ gfm: true,
19
+ extensions: {
20
+ block: [],
21
+ inline: [],
22
+ childTokens: {},
23
+ renderers: {},
24
+ startBlock: [],
25
+ startInline: []
12
26
  }
13
- }
14
- })
15
- .use(markedAlert())
16
- .use(markedFootnote())
17
- .use(markedMath())
18
- .use(markedSubSup())
19
- .use(markedList())
20
- .use(markedTable());
21
- const blockLexer = new Lexer({
22
- extensions: {
23
- childTokens: {},
24
- renderers: {},
25
- block: [markedFootnote().extensions[0].tokenizer, markedTable().extensions[0].tokenizer]
26
- }
27
- });
27
+ };
28
+ ext.forEach(({ extensions }) => {
29
+ extensions.forEach(({ level, name, tokenizer, ...rest }) => {
30
+ if ('start' in rest && rest.start) {
31
+ if (level === 'block') {
32
+ options.extensions.startBlock.push(rest.start);
33
+ }
34
+ else {
35
+ options.extensions.startInline.push(rest.start);
36
+ }
37
+ }
38
+ if (tokenizer) {
39
+ if (level === 'block') {
40
+ options.extensions.block.push(tokenizer);
41
+ }
42
+ else {
43
+ options.extensions.inline.push(tokenizer);
44
+ }
45
+ }
46
+ });
47
+ });
48
+ return options;
49
+ };
50
+ const blockLexer = new Lexer(parseExtensions(markedFootnote(), markedTable()));
28
51
  export const lex = (markdown) => {
29
- return completeLexer
30
- .lexer(markdown)
52
+ return new Lexer(parseExtensions(...extensions))
53
+ .lex(markdown)
31
54
  .filter((token) => token.type !== 'space' && token.type !== 'footnote');
32
55
  };
33
56
  export const parseBlocks = (markdown) => {
@@ -1,6 +1,11 @@
1
- import type { TokenizerAndRendererExtension } from 'marked';
1
+ import type { TokenizerExtensionFunction, TokenizerStartFunction } from 'marked';
2
2
  export declare function markedMath(): {
3
- extensions: TokenizerAndRendererExtension<string, string>[];
3
+ extensions: Array<{
4
+ name: string;
5
+ level: 'block' | 'inline';
6
+ start?: TokenizerStartFunction;
7
+ tokenizer: TokenizerExtensionFunction;
8
+ }>;
4
9
  };
5
10
  export type MathToken = {
6
11
  type: 'math';
@@ -1,9 +1,25 @@
1
- const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
1
+ // const inlineRule =
2
+ // /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
2
3
  const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1/; // Non-standard, even if there are no spaces before and after $ or $$, try to parse
3
4
  const blockRule = /^(\${1,2})\n((?:\\[\s\S]|[^\\])+?)\n\1(?:\n|$)/;
4
5
  export function markedMath() {
5
6
  return {
6
7
  extensions: [
8
+ {
9
+ name: 'block-math',
10
+ level: 'block',
11
+ tokenizer(src) {
12
+ const match = src.match(blockRule);
13
+ if (match) {
14
+ return {
15
+ type: 'math',
16
+ isInline: false,
17
+ raw: match[0],
18
+ text: match[2].trim()
19
+ };
20
+ }
21
+ }
22
+ },
7
23
  {
8
24
  name: 'inline-math',
9
25
  level: 'inline',
@@ -36,21 +52,6 @@ export function markedMath() {
36
52
  };
37
53
  }
38
54
  }
39
- },
40
- {
41
- name: 'block-math',
42
- level: 'block',
43
- tokenizer(src) {
44
- const match = src.match(blockRule);
45
- if (match) {
46
- return {
47
- type: 'math',
48
- isInline: false,
49
- raw: match[0],
50
- text: match[2].trim()
51
- };
52
- }
53
- }
54
55
  }
55
56
  ]
56
57
  };
@@ -1,10 +1,10 @@
1
- import type { TokenizerExtensionFunction } from 'marked';
1
+ import type { TokenizerExtensionFunction, TokenizerStartFunction } from 'marked';
2
2
  export default function markedSubSup(): {
3
3
  extensions: {
4
4
  name: string;
5
5
  level: 'inline';
6
6
  tokenizer: TokenizerExtensionFunction;
7
- start?: (src: string) => number | undefined;
7
+ start?: TokenizerStartFunction;
8
8
  }[];
9
9
  };
10
10
  /**
@@ -1,4 +1,4 @@
1
- import type { TokenizerExtensionFunction } from 'marked';
1
+ import type { TokenizerExtensionFunction, TokenizerStartFunction } from 'marked';
2
2
  export interface SpanTableOptions {
3
3
  useTheadTbody?: boolean;
4
4
  useTfoot?: boolean;
@@ -59,7 +59,7 @@ export declare function markedTable(options?: SpanTableOptions): {
59
59
  extensions: {
60
60
  name: string;
61
61
  level: 'block' | 'inline';
62
- start: (src: string) => number | undefined;
62
+ start: TokenizerStartFunction;
63
63
  tokenizer: TokenizerExtensionFunction;
64
64
  }[];
65
65
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-streamdown",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",