svelte-streamdown 2.2.4 → 2.2.6

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
@@ -386,6 +386,7 @@ This heading will use a custom component!`;
386
386
  | `animation.duration` | `number` | `500` | Animation duration in milliseconds |
387
387
  | `animation.timingFunction`| `'ease' \| 'ease-in' \| 'ease-out' \| 'ease-in-out' \| 'linear'` | `'ease-in'` | CSS timing function for animations |
388
388
  | `animation.tokenize` | `'word' \| 'char'` | `'word'` | Tokenization method for text animations |
389
+ | `animation.animateOnMount` | `boolean` | `false` | Run the token animation on mount or not, useful if you render the Streamdown component in the same time as the first token is receive from the LLM |
389
390
 
390
391
  ### Custom Component Props
391
392
 
@@ -5,11 +5,9 @@
5
5
  let { children }: { children: Snippet } = $props();
6
6
 
7
7
  const streamdown = useStreamdown();
8
-
9
- const isMounted = streamdown.isMounted;
10
8
  </script>
11
9
 
12
- {#if isMounted}
10
+ {#if streamdown.isMounted}
13
11
  <div style={streamdown.animationBlockStyle}>
14
12
  {@render children()}
15
13
  </div>
@@ -16,12 +16,11 @@
16
16
 
17
17
  return text.split(splitRegex).filter((token) => token.length > 0);
18
18
  };
19
+
19
20
  const tokens = $derived(tokenizeNewContent(text));
20
-
21
- const isMounted = streamdown.isMounted;
22
21
  </script>
23
22
 
24
- {#if isMounted}
23
+ {#if streamdown.isMounted}
25
24
  <span>
26
25
  {#each tokens as token}
27
26
  <span style={streamdown.animationTextStyle}>
@@ -95,7 +95,7 @@
95
95
  {/snippet}
96
96
  {#snippet Skeleton(lines: string[])}
97
97
  {#each lines as line}
98
- <span class={streamdown.theme.code.line}>
98
+ <span class={streamdown.theme.code.skeleton}>
99
99
  {line.trim().length > 0 ? line : '\u200B'}
100
100
  </span>
101
101
  {/each}
@@ -12,8 +12,6 @@
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;
17
15
  </script>
18
16
 
19
17
  {#if token.type === 'heading'}
@@ -93,7 +91,7 @@
93
91
  {:else if token.type === 'list_item'}
94
92
  <Slot props={{ children, token }} render={streamdown.snippets.li}>
95
93
  <li
96
- style={isMounted ? streamdown.animationBlockStyle : undefined}
94
+ style={streamdown.isMounted ? streamdown.animationBlockStyle : undefined}
97
95
  style:list-style-type={token.task ? 'none' : undefined}
98
96
  {...token.value && !token.task ? { value: token.value } : {}}
99
97
  class={streamdown.theme.li.base}
@@ -79,7 +79,6 @@
79
79
  off();
80
80
  };
81
81
  };
82
- const isMounted = streamdown.isMounted;
83
82
  </script>
84
83
 
85
84
  {#if isOpen}
@@ -113,7 +112,7 @@
113
112
  render={streamdown.snippets.footnoteRef}
114
113
  >
115
114
  <button
116
- style={isMounted ? streamdown.animationBlockStyle : ''}
115
+ style={streamdown.isMounted ? streamdown.animationBlockStyle : ''}
117
116
  bind:this={reference}
118
117
  class={streamdown.theme.footnoteRef.base}
119
118
  onclick={() => (isOpen = !isOpen)}
@@ -45,13 +45,11 @@
45
45
  });
46
46
  }
47
47
  });
48
-
49
- const isMounted = streamdown.isMounted;
50
48
  </script>
51
49
 
52
50
  {#if isInline}
53
51
  <span
54
- style={isMounted ? streamdown.animationBlockStyle : ''}
52
+ style={streamdown.isMounted ? streamdown.animationBlockStyle : ''}
55
53
  bind:this={inner}
56
54
  class={streamdown.theme.math.inline}
57
55
  >
@@ -197,9 +197,6 @@
197
197
  panzoom.zoomToFit();
198
198
  } catch (err) {
199
199
  const sanitizedCode = sanitizeMermaidCode(code);
200
- console.error('Mermaid rendering error:', err);
201
- console.error('Original code:', code);
202
- console.error('Sanitized code:', sanitizedCode);
203
200
  }
204
201
  };
205
202
  </script>
@@ -83,6 +83,7 @@
83
83
  };
84
84
  return {
85
85
  enabled: true,
86
+ animateOnMount: animation.animateOnMount ?? false,
86
87
  type: animation.type || 'blur',
87
88
  duration: animation.duration || 500,
88
89
  timingFunction: animation.timingFunction || 'ease-in',
@@ -103,6 +103,7 @@ export type StreamdownProps = {
103
103
  };
104
104
  renderHtml?: boolean | ((token: Tokens.HTML | Tokens.Tag) => string);
105
105
  animation?: {
106
+ animateOnMount?: boolean;
106
107
  enabled?: boolean;
107
108
  type?: 'fade' | 'blur' | 'typewriter' | 'slideUp' | 'slideDown';
108
109
  duration?: number;
@@ -4,7 +4,7 @@ export class StreamdownContext {
4
4
  refs: new Map(),
5
5
  footnotes: new Map()
6
6
  };
7
- isMounted = $state(false);
7
+ isMounted = false;
8
8
  animationTextStyle = $derived(this.animation.enabled
9
9
  ? `animation-name: sd-${this.animation.type};
10
10
  animation-duration: ${this.animation.duration}ms;
@@ -24,6 +24,9 @@ animation-fill-mode: forwards;`
24
24
  constructor(props) {
25
25
  bind(this, props);
26
26
  setContext('streamdown', this);
27
+ if (this.animation.animateOnMount) {
28
+ this.isMounted = true;
29
+ }
27
30
  onMount(() => {
28
31
  this.isMounted = true;
29
32
  });
package/dist/theme.js CHANGED
@@ -43,7 +43,7 @@ export const theme = {
43
43
  header: 'flex items-center justify-between bg-gray-100/80 p-2 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 scale-y-90 animate-pulse whitespace-nowrap inline-block',
46
+ skeleton: 'block rounded-md font-mono text-transparent bg-gray-200 scale-y-90 animate-pulse whitespace-nowrap',
47
47
  pre: 'overflow-x-auto font-mono p-0 bg-gray-100/40',
48
48
  line: 'block'
49
49
  },
@@ -171,7 +171,7 @@ export const shadcnTheme = {
171
171
  header: 'flex items-center justify-between bg-muted/80 px-2 py-1 text-muted-foreground text-xs',
172
172
  button: 'cursor-pointer size-6 p-1 text-muted-foreground transition-all hover:text-foreground rounded hover:bg-muted',
173
173
  language: 'ml-1 font-mono lowercase',
174
- skeleton: 'rounded-md font-mono text-transparent bg-border/80 scale-y-90 w-fit animate-pulse whitespace-nowrap inline-block',
174
+ skeleton: 'block rounded-md font-mono text-transparent bg-border/80 scale-y-90 w-fit animate-pulse whitespace-nowrap',
175
175
  pre: 'overflow-x-auto font-mono p-0 bg-muted/40',
176
176
  line: 'block '
177
177
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-streamdown",
3
- "version": "2.2.4",
3
+ "version": "2.2.6",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",