markstream-svelte 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.
@@ -55,6 +55,8 @@
55
55
  let rendering = $state(false)
56
56
  let rerenderQueued = $state(false)
57
57
  let rerenderForce = $state(false)
58
+ let renderScheduled = $state(false)
59
+ let renderScheduledForce = $state(false)
58
60
  let hasPreview = $state(false)
59
61
  let copied = $state(false)
60
62
  let collapsed = $state(false)
@@ -111,7 +113,16 @@
111
113
  function queueInfographicRender(force = false) {
112
114
  if (!mounted || !renderHost || collapsed || showSource || !source.trim())
113
115
  return
114
- void tick().then(() => renderInfographic(force))
116
+ renderScheduledForce = renderScheduledForce || force
117
+ if (renderScheduled)
118
+ return
119
+ renderScheduled = true
120
+ void tick().then(() => {
121
+ renderScheduled = false
122
+ const forceNext = renderScheduledForce
123
+ renderScheduledForce = false
124
+ return renderInfographic(forceNext)
125
+ })
115
126
  }
116
127
 
117
128
  async function renderInfographic(force = false) {
@@ -128,7 +139,9 @@
128
139
  return
129
140
  }
130
141
 
131
- const signature = `${source}\n${resolvedIsDark}\n${final}\n${progressivePreview}`
142
+ const renderSource = source
143
+ const renderFinal = final
144
+ const signature = `${renderSource}\n${resolvedIsDark}\n${renderFinal}\n${progressivePreview}`
132
145
  if (!force && signature === lastCompletedRenderSignature && hasPreview)
133
146
  return
134
147
  if (!force && signature === lastSuppressedErrorSignature)
@@ -148,6 +161,8 @@
148
161
  rendering = true
149
162
  if (shouldShowError)
150
163
  renderError = ''
164
+ let nextInstance: any = null
165
+ let previousChildren: ChildNode[] | null = null
151
166
 
152
167
  try {
153
168
  const InfographicClass = await getInfographic()
@@ -155,17 +170,22 @@
155
170
  return
156
171
  if (!InfographicClass)
157
172
  throw new Error('Infographic renderer is not available.')
173
+ const currentSignature = `${source}\n${resolvedIsDark}\n${final}\n${progressivePreview}`
174
+ const canRender = signature === currentSignature
175
+ || (!renderFinal && resolvedLoading && source.startsWith(renderSource))
176
+ if (!canRender)
177
+ return
158
178
 
159
- destroyInstance()
160
- clearElement(renderHost)
161
- instance = new InfographicClass({
179
+ previousChildren = Array.from(renderHost.childNodes)
180
+ nextInstance = new InfographicClass({
162
181
  container: renderHost,
163
182
  width: '100%',
164
183
  height: '100%',
165
184
  })
166
185
 
167
186
  let renderErrorMessage = ''
168
- instance.on?.('error', (error: unknown) => {
187
+ let renderCompleted = false
188
+ nextInstance.on?.('error', (error: unknown) => {
169
189
  const errors = Array.isArray(error) ? error : [error]
170
190
  renderErrorMessage = errors
171
191
  .map((item) => {
@@ -180,15 +200,24 @@
180
200
  .filter(Boolean)
181
201
  .join('; ')
182
202
  })
203
+ nextInstance.on?.('rendered', () => {
204
+ renderCompleted = true
205
+ })
183
206
 
184
- instance.render(source)
207
+ nextInstance.render(renderSource)
185
208
  if (renderErrorMessage)
186
209
  throw new Error(renderErrorMessage)
187
- await tick()
188
- if (!mounted || token !== renderToken || collapsed || showSource || !renderHost)
189
- return
190
- if (!renderHost.querySelector('svg') && !renderHost.childElementCount)
210
+ const nextChildren = Array.from(renderHost.childNodes)
211
+ const replacedChildren = nextChildren.length > 0 && (
212
+ nextChildren.length !== previousChildren.length
213
+ || nextChildren.some((child, index) => child !== previousChildren?.[index])
214
+ )
215
+ if (!renderCompleted && !replacedChildren)
191
216
  throw new Error('Infographic render returned empty output.')
217
+
218
+ instance?.destroy?.()
219
+ instance = nextInstance
220
+ nextInstance = null
192
221
  hasPreview = true
193
222
  renderError = ''
194
223
  lastCompletedRenderSignature = signature
@@ -196,8 +225,11 @@
196
225
  }
197
226
  catch (error) {
198
227
  if (token === renderToken) {
228
+ nextInstance?.destroy?.()
229
+ nextInstance = null
199
230
  lastCompletedRenderSignature = ''
200
- if (shouldShowError) {
231
+ const currentSignature = `${source}\n${resolvedIsDark}\n${final}\n${progressivePreview}`
232
+ if (shouldShowError && signature === currentSignature) {
201
233
  lastSuppressedErrorSignature = ''
202
234
  destroyInstance()
203
235
  clearElement(renderHost)
@@ -205,11 +237,15 @@
205
237
  renderError = error instanceof Error ? error.message : String(error)
206
238
  }
207
239
  else {
208
- lastSuppressedErrorSignature = signature
240
+ if (previousChildren && renderHost)
241
+ renderHost.replaceChildren(...previousChildren)
242
+ if (signature === currentSignature)
243
+ lastSuppressedErrorSignature = signature
209
244
  }
210
245
  }
211
246
  }
212
247
  finally {
248
+ nextInstance?.destroy?.()
213
249
  if (token === renderToken) {
214
250
  rendering = false
215
251
  activeRenderSignature = ''
@@ -239,6 +275,8 @@
239
275
  rendering = false
240
276
  rerenderQueued = false
241
277
  rerenderForce = false
278
+ renderScheduled = false
279
+ renderScheduledForce = false
242
280
  hasPreview = false
243
281
  renderError = ''
244
282
  activeRenderSignature = ''
@@ -417,6 +455,9 @@
417
455
  </div>
418
456
  {/if}
419
457
  <div class="infographic-render" style={previewStyle}>
458
+ {#if !hasPreview && !renderError}
459
+ <pre class="infographic-source-code infographic-pending-source"><code>{source}</code></pre>
460
+ {/if}
420
461
  <div bind:this={renderHost} style={transformStyle}></div>
421
462
  {#if renderError}
422
463
  <p class="d2-error">{renderError}</p>
package/dist/index.css CHANGED
@@ -2126,6 +2126,15 @@ body > div[id^="dmermaid-"] {
2126
2126
  text-align: center;
2127
2127
  }
2128
2128
 
2129
+ .markstream-svelte .infographic-pending-source {
2130
+ position: absolute;
2131
+ inset: 0;
2132
+ z-index: 1;
2133
+ overflow: auto;
2134
+ padding: var(--ms-inset-panel-body);
2135
+ text-align: left;
2136
+ }
2137
+
2129
2138
  .markstream-svelte .infographic-render > div {
2130
2139
  transition: transform 120ms ease;
2131
2140
  }
package/dist/index.px.css CHANGED
@@ -2126,6 +2126,15 @@ body > div[id^="dmermaid-"] {
2126
2126
  text-align: center;
2127
2127
  }
2128
2128
 
2129
+ .markstream-svelte .infographic-pending-source {
2130
+ position: absolute;
2131
+ inset: 0;
2132
+ z-index: 1;
2133
+ overflow: auto;
2134
+ padding: var(--ms-inset-panel-body);
2135
+ text-align: left;
2136
+ }
2137
+
2129
2138
  .markstream-svelte .infographic-render > div {
2130
2139
  transition: transform 120ms ease;
2131
2140
  }
@@ -2126,6 +2126,15 @@ body > div[id^="dmermaid-"] {
2126
2126
  text-align: center;
2127
2127
  }
2128
2128
 
2129
+ .markstream-svelte .infographic-pending-source {
2130
+ position: absolute;
2131
+ inset: 0;
2132
+ z-index: 1;
2133
+ overflow: auto;
2134
+ padding: var(--ms-inset-panel-body);
2135
+ text-align: left;
2136
+ }
2137
+
2129
2138
  .markstream-svelte .infographic-render > div {
2130
2139
  transition: transform 120ms ease;
2131
2140
  }
@@ -22,7 +22,6 @@ export interface CodeBlockOptions {
22
22
  disableLineNumbers?: boolean;
23
23
  overflow?: 'scroll' | 'wrap';
24
24
  disableVirtualizationBuffers?: boolean;
25
- preferredHighlighter?: 'shiki-js' | 'shiki-wasm';
26
25
  useCSSClasses?: boolean;
27
26
  useTokenTransformer?: boolean;
28
27
  tokenizeMaxLineLength?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "markstream-svelte",
3
3
  "type": "module",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
5
5
  "description": "Svelte 5 and SvelteKit streaming Markdown renderer for AI chat, LLM token streams, SSE/WebSocket output, incomplete Markdown, Mermaid, KaTeX, stream-diffs powered code blocks, and custom Svelte components.",
6
6
  "author": "Simon He",
7
7
  "license": "MIT",
@@ -100,8 +100,8 @@
100
100
  },
101
101
  "dependencies": {
102
102
  "@floating-ui/dom": "^1.8.0",
103
- "markstream-core": "2.0.0",
104
- "stream-markdown-parser": "1.2.8"
103
+ "stream-markdown-parser": "1.2.9",
104
+ "markstream-core": "2.0.1"
105
105
  },
106
106
  "devDependencies": {
107
107
  "@sveltejs/package": "^2.5.8",