svelte-streamdown 1.0.8 → 2.0.0
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 +155 -140
- package/dist/Block.svelte +17 -41
- package/dist/Elements/Alert.svelte +1 -2
- package/dist/Elements/Code.svelte +3 -5
- package/dist/Elements/Code.svelte.d.ts +0 -2
- package/dist/Elements/Element.svelte +170 -42
- package/dist/Elements/FootnoteRef.svelte +126 -0
- package/dist/Elements/FootnoteRef.svelte.d.ts +7 -0
- package/dist/Elements/Image.svelte +4 -4
- package/dist/Elements/{A.svelte → Link.svelte} +4 -4
- package/dist/Elements/{A.svelte.d.ts → Link.svelte.d.ts} +3 -3
- package/dist/Elements/Math.svelte +13 -24
- package/dist/Elements/Math.svelte.d.ts +0 -2
- package/dist/Elements/Mermaid.svelte +105 -115
- package/dist/Elements/Mermaid.svelte.d.ts +0 -2
- package/dist/Elements/Table.svelte +1 -1
- package/dist/Elements/index.d.ts +5 -24
- package/dist/Elements/index.js +5 -24
- package/dist/Streamdown.d.ts +52 -10
- package/dist/Streamdown.js +19 -1
- package/dist/Streamdown.svelte +2 -34
- package/dist/Streamdown.svelte.d.ts +1 -14
- package/dist/marked/index.d.ts +6 -10
- package/dist/marked/index.js +29 -17
- package/dist/marked/marked-alert.d.ts +2 -2
- package/dist/marked/marked-alert.js +11 -24
- package/dist/marked/marked-footnotes.d.ts +1 -0
- package/dist/marked/marked-footnotes.js +27 -8
- package/dist/marked/marked-list.d.ts +36 -0
- package/dist/marked/marked-list.js +232 -0
- package/dist/marked/marked-math.js +1 -4
- package/dist/marked/marked-subsup.d.ts +28 -0
- package/dist/marked/marked-subsup.js +45 -0
- package/dist/marked/marked-table.d.ts +59 -0
- package/dist/marked/marked-table.js +495 -0
- package/dist/theme.d.ts +54 -30
- package/dist/theme.js +51 -35
- package/dist/utils/panzoom.svelte.d.ts +17 -18
- package/dist/utils/panzoom.svelte.js +0 -2
- package/dist/utils/parse-incomplete-markdown.js +157 -0
- package/dist/utils/useClickOutside.svelte.d.ts +8 -0
- package/dist/utils/useClickOutside.svelte.js +41 -0
- package/dist/utils/useKeyDown.svelte.d.ts +5 -0
- package/dist/utils/useKeyDown.svelte.js +23 -0
- package/package.json +2 -1
- package/dist/Elements/Blockquote.svelte +0 -28
- package/dist/Elements/Blockquote.svelte.d.ts +0 -9
- package/dist/Elements/Del.svelte +0 -28
- package/dist/Elements/Del.svelte.d.ts +0 -9
- package/dist/Elements/Em.svelte +0 -28
- package/dist/Elements/Em.svelte.d.ts +0 -9
- package/dist/Elements/Heading.svelte +0 -25
- package/dist/Elements/Heading.svelte.d.ts +0 -9
- package/dist/Elements/Hr.svelte +0 -26
- package/dist/Elements/Hr.svelte.d.ts +0 -9
- package/dist/Elements/InlineCode.svelte +0 -28
- package/dist/Elements/InlineCode.svelte.d.ts +0 -9
- package/dist/Elements/Li.svelte +0 -28
- package/dist/Elements/Li.svelte.d.ts +0 -9
- package/dist/Elements/Ol.svelte +0 -30
- package/dist/Elements/Ol.svelte.d.ts +0 -9
- package/dist/Elements/P.svelte +0 -28
- package/dist/Elements/P.svelte.d.ts +0 -9
- package/dist/Elements/Strong.svelte +0 -28
- package/dist/Elements/Strong.svelte.d.ts +0 -9
- package/dist/Elements/Sub.svelte +0 -27
- package/dist/Elements/Sub.svelte.d.ts +0 -8
- package/dist/Elements/Sup.svelte +0 -28
- package/dist/Elements/Sup.svelte.d.ts +0 -8
- package/dist/Elements/Tbody.svelte +0 -24
- package/dist/Elements/Tbody.svelte.d.ts +0 -7
- package/dist/Elements/Td.svelte +0 -28
- package/dist/Elements/Td.svelte.d.ts +0 -9
- package/dist/Elements/Th.svelte +0 -28
- package/dist/Elements/Th.svelte.d.ts +0 -9
- package/dist/Elements/Thead.svelte +0 -27
- package/dist/Elements/Thead.svelte.d.ts +0 -9
- package/dist/Elements/Tr.svelte +0 -27
- package/dist/Elements/Tr.svelte.d.ts +0 -9
- package/dist/Elements/Ul.svelte +0 -28
- package/dist/Elements/Ul.svelte.d.ts +0 -9
- /package/dist/{hightlighter.svelte.d.ts → utils/hightlighter.svelte.d.ts} +0 -0
- /package/dist/{hightlighter.svelte.js → utils/hightlighter.svelte.js} +0 -0
package/README.md
CHANGED
|
@@ -20,6 +20,27 @@ Perfect for AI-powered applications that need to stream and render markdown cont
|
|
|
20
20
|
|
|
21
21
|
## ✨ Main Features
|
|
22
22
|
|
|
23
|
+
|
|
24
|
+
### 🔄 Streaming-Optimized
|
|
25
|
+
|
|
26
|
+
- **Incomplete Markdown Parsing**: Handles unterminated blocks gracefully
|
|
27
|
+
- **Progressive Rendering**: Perfect for streaming AI responses
|
|
28
|
+
- **Real-time Updates**: Optimized for dynamic content
|
|
29
|
+
|
|
30
|
+
### 🔒 Security Hardening
|
|
31
|
+
|
|
32
|
+
- **Image Origin Control**: Whitelist allowed image sources
|
|
33
|
+
- **Link Safety**: Control link destinations
|
|
34
|
+
- **HTML Sanitization**: Prevent XSS attacks
|
|
35
|
+
|
|
36
|
+
### 🎯 Fully Customizable Components & Theming
|
|
37
|
+
|
|
38
|
+
- **Every component customizable** with Svelte snippets
|
|
39
|
+
- **Granular theming system** - customize every part of every component
|
|
40
|
+
- Override default styling and behavior for any markdown element
|
|
41
|
+
- Full control over rendering with type-safe props
|
|
42
|
+
- Seamless integration with your design system
|
|
43
|
+
|
|
23
44
|
### 🎨 Built-in Typography Styles
|
|
24
45
|
|
|
25
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.
|
|
@@ -28,9 +49,16 @@ Beautiful, responsive typography with **built-in Tailwind CSS classes** for head
|
|
|
28
49
|
|
|
29
50
|
Full support for GitHub Flavored Markdown including:
|
|
30
51
|
|
|
31
|
-
- Task lists
|
|
32
52
|
- Tables
|
|
33
|
-
- Strikethrough
|
|
53
|
+
- ~~Strikethrough~~
|
|
54
|
+
- Subscript (H~2~O)
|
|
55
|
+
- Superscript (E = mc^2^)
|
|
56
|
+
- Footnotes [^1]
|
|
57
|
+
|
|
58
|
+
[^1]:
|
|
59
|
+
Reference render in a popover by default.
|
|
60
|
+
with _rich_ **content** support
|
|
61
|
+
and multiline
|
|
34
62
|
|
|
35
63
|
### 💻 Interactive Code Blocks
|
|
36
64
|
|
|
@@ -91,48 +119,131 @@ pie title Project Time Allocation
|
|
|
91
119
|
"Meetings" : 15
|
|
92
120
|
```
|
|
93
121
|
|
|
94
|
-
###
|
|
122
|
+
### Complex table support
|
|
95
123
|
|
|
96
|
-
|
|
97
|
-
> Native support for Github style Alert
|
|
124
|
+
#### Colspan
|
|
98
125
|
|
|
99
|
-
|
|
126
|
+
| H1 | H2 | H3 |
|
|
127
|
+
| ------------------------- | --- | --- |
|
|
128
|
+
| This cell spans 3 columns |||
|
|
100
129
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
130
|
+
| Header 1 | Header 2 | Header 3 |
|
|
131
|
+
| ------------------------- | -------- | -------- |
|
|
132
|
+
| This cell spans 2 columns || Normal
|
|
133
|
+
| Normal | Normal | Normal |
|
|
104
134
|
|
|
105
|
-
|
|
135
|
+
#### Rowspan
|
|
136
|
+
| Header 1 | Header 2 |
|
|
137
|
+
| --------------- | -------- |
|
|
138
|
+
| This cell spans | Cell A |
|
|
139
|
+
| two rows ^ | Cell B |
|
|
140
|
+
#### Footer
|
|
141
|
+
| Header 1 | Header 2 |
|
|
142
|
+
| --------------- | -------- |
|
|
143
|
+
| Cell B | Cell A |
|
|
144
|
+
| --------------- | -------- |
|
|
145
|
+
| Footer ||
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
- **Link Safety**: Control link destinations
|
|
109
|
-
- **HTML Sanitization**: Prevent XSS attacks
|
|
147
|
+
#### Column alignment
|
|
110
148
|
|
|
111
|
-
|
|
149
|
+
| Left | Center | Right |
|
|
150
|
+
| :--- | :----: | ----: |
|
|
151
|
+
| A | B | C |
|
|
152
|
+
|
|
153
|
+
#### Multiple headers and very complex layout
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
| Product Category ||| Sales Data Q1-Q4 2024 ||||
|
|
157
|
+
| Product | Region || Q1 | Q2 | Q3 | Q4 |
|
|
158
|
+
| Name | Type | Area | Revenue | Revenue | Revenue | Revenue |
|
|
159
|
+
|-------------|---------|------------|---------|---------|---------|---------|
|
|
160
|
+
| Laptop Pro | Electronics | North America || $45,000 | $52,000 | $48,000 |
|
|
161
|
+
| Laptop Pro ^ | ^ | Europe | $32,000 | $38,000 | $41,000 | $44,000 |
|
|
162
|
+
| Laptop Pro ^ | ^ | Asia || $28,000 | $35,000 | $42,000 |
|
|
163
|
+
| Office Chair | Furniture | North America | $15,000 | $18,000 | $16,000 | $17,000 |
|
|
164
|
+
| Office Chair ^ | ^ | Europe | $12,000 | $14,000 | $15,000 | $16,000 |
|
|
165
|
+
| Wireless Mouse | Electronics | Global ||| $25,000 | $28,000 |
|
|
166
|
+
|-------------|---------|------------|---------|---------|---------|---------|
|
|
167
|
+
| **Total Revenue** ||| **$152,000** | **$185,000** | **$187,000** | **$205,000** |
|
|
168
|
+
|
|
169
|
+
### Complex list support
|
|
170
|
+
|
|
171
|
+
#### decimal
|
|
172
|
+
|
|
173
|
+
1. First item
|
|
174
|
+
2. Second item
|
|
175
|
+
3. Third item
|
|
176
|
+
|
|
177
|
+
#### lower-alpha
|
|
178
|
+
|
|
179
|
+
a. First item
|
|
180
|
+
b. Second item
|
|
181
|
+
c. Third item
|
|
182
|
+
|
|
183
|
+
#### upper-alpha
|
|
184
|
+
|
|
185
|
+
A. First item
|
|
186
|
+
B. Second item
|
|
187
|
+
C. Third item
|
|
188
|
+
|
|
189
|
+
#### lower-roman
|
|
190
|
+
|
|
191
|
+
i. First item
|
|
192
|
+
ii. Second item
|
|
193
|
+
iii. Third item
|
|
194
|
+
|
|
195
|
+
#### upper-roman
|
|
196
|
+
|
|
197
|
+
I. First item
|
|
198
|
+
II. Second item
|
|
199
|
+
III. Third item
|
|
200
|
+
|
|
201
|
+
#### Nested Lists
|
|
202
|
+
|
|
203
|
+
1. First level (numeric)
|
|
204
|
+
a. Second level (lowercase alpha)
|
|
205
|
+
i. Third level (lowercase roman)
|
|
206
|
+
- Fourth level (bullet)
|
|
207
|
+
I. Fifth level (uppercase roman)
|
|
208
|
+
A. Sixth level (uppercase alpha)
|
|
209
|
+
|
|
210
|
+
2. Back to the first level
|
|
211
|
+
|
|
212
|
+
#### Task List
|
|
213
|
+
|
|
214
|
+
- [ ] Uncompleted task
|
|
215
|
+
- [x] Completed task
|
|
216
|
+
- [ ] Another uncompleted task
|
|
217
|
+
- [ ] Nested uncompleted subtask
|
|
218
|
+
- [x] Nested completed subtask
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
### Alert Support
|
|
222
|
+
|
|
223
|
+
> [!IMPORTANT]
|
|
224
|
+
> Native support for Github style Alert
|
|
112
225
|
|
|
113
|
-
- **Every component customizable** with Svelte snippets
|
|
114
|
-
- **Granular theming system** - customize every part of every component
|
|
115
|
-
- Override default styling and behavior for any markdown element
|
|
116
|
-
- Full control over rendering with type-safe props
|
|
117
|
-
- Seamless integration with your design system
|
|
118
226
|
|
|
119
227
|
## 🔄 Differences from Original React Version
|
|
120
228
|
|
|
121
229
|
This Svelte port maintains feature parity with the original [Streamdown](https://streamdown.ai/) while adapting to Svelte's patterns:
|
|
122
230
|
|
|
123
|
-
| Aspect | Original (React)
|
|
124
|
-
| ----------------- |
|
|
125
|
-
| **Framework** | React
|
|
126
|
-
| **Component API** | JSX Components
|
|
127
|
-
| **Styling** | Tailwind CSS
|
|
128
|
-
| **Context** | React Context
|
|
129
|
-
| **Build System** | Vite/React
|
|
130
|
-
| **TypeScript** | Full TS support
|
|
231
|
+
| Aspect | Original (React) | Svelte Port |
|
|
232
|
+
| ----------------- | ------------------------ | ------------------------- |
|
|
233
|
+
| **Framework** | React | Svelte 5 |
|
|
234
|
+
| **Component API** | JSX Components | Svelte Snippets |
|
|
235
|
+
| **Styling** | Tailwind CSS | Tailwind CSS (compatible) |
|
|
236
|
+
| **Context** | React Context | Svelte Context |
|
|
237
|
+
| **Build System** | Vite/React | Vite/SvelteKit |
|
|
238
|
+
| **TypeScript** | Full TS support | Full TS support |
|
|
239
|
+
| **Engine** | Remark / Rehype + marked | marked only |
|
|
131
240
|
|
|
132
241
|
### Tailwind CSS Setup
|
|
133
242
|
|
|
134
243
|
> [!NOTE]
|
|
135
244
|
> 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
|
+
> 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.
|
|
246
|
+
> This ensures that all Streamdown's default styling is included in your Tailwind build process.
|
|
136
247
|
|
|
137
248
|
```css
|
|
138
249
|
@import 'tailwindcss';
|
|
@@ -140,10 +251,6 @@ This Svelte port maintains feature parity with the original [Streamdown](https:/
|
|
|
140
251
|
@source "../node_modules/svelte-streamdown/**/*";
|
|
141
252
|
```
|
|
142
253
|
|
|
143
|
-
This ensures that all Streamdown's default styling is included in your Tailwind build process.
|
|
144
|
-
|
|
145
|
-
> **Note:** 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.
|
|
146
|
-
|
|
147
254
|
## 🚀 Quick Start
|
|
148
255
|
|
|
149
256
|
### Basic Usage
|
|
@@ -178,13 +285,13 @@ This heading will use a custom component!`;
|
|
|
178
285
|
// Custom heading component
|
|
179
286
|
</script>
|
|
180
287
|
|
|
181
|
-
{#snippet
|
|
182
|
-
<h1 class="mb-4 text-4xl font-bold text-blue-600" {...props}>
|
|
183
|
-
{children}
|
|
288
|
+
{#snippet customHeading({ children, token })}
|
|
289
|
+
<h1 class="mb-4 text-4xl font-bold text-blue-600" {...token.props}>
|
|
290
|
+
{@render children()}
|
|
184
291
|
</h1>
|
|
185
292
|
{/snippet}
|
|
186
293
|
|
|
187
|
-
<Streamdown {content}
|
|
294
|
+
<Streamdown {content} heading={customHeading} />
|
|
188
295
|
```
|
|
189
296
|
|
|
190
297
|
### Security Configuration
|
|
@@ -214,9 +321,6 @@ This heading will use a custom component!`;
|
|
|
214
321
|
| `defaultOrigin` | `string` | - | Default origin for relative URLs |
|
|
215
322
|
| `allowedLinkPrefixes` | `string[]` | `['*']` | Allowed URL prefixes for links |
|
|
216
323
|
| `allowedImagePrefixes` | `string[]` | `['*']` | Allowed URL prefixes for images |
|
|
217
|
-
| `allowElement` | `AllowElement \| null` | - | Custom element filtering function |
|
|
218
|
-
| `allowedElements` | `readonly string[] \| null` | - | Whitelist of allowed HTML elements |
|
|
219
|
-
| `disallowedElements` | `readonly string[] \| null` | - | Blacklist of disallowed HTML elements |
|
|
220
324
|
| `skipHtml` | `boolean` | - | Skip HTML parsing entirely |
|
|
221
325
|
| `unwrapDisallowed` | `boolean` | - | Unwrap instead of removing disallowed elements |
|
|
222
326
|
| `urlTransform` | `UrlTransform \| null` | - | Custom URL transformation function |
|
|
@@ -226,14 +330,13 @@ This heading will use a custom component!`;
|
|
|
226
330
|
| `shikiTheme` | `BundledTheme` | `'github-light'` | Code highlighting theme |
|
|
227
331
|
| `mermaidConfig` | `MermaidConfig` | - | Mermaid diagram configuration |
|
|
228
332
|
| `katexConfig` | `KatexOptions \| ((inline: boolean) => KatexOptions)` | - | KaTeX math rendering options |
|
|
229
|
-
| `remarkPlugins` | `PluggableList` | - | Additional remark plugins |
|
|
230
|
-
| `rehypePlugins` | `PluggableList` | - | Additional rehype plugins |
|
|
231
|
-
| `remarkRehypeOptions` | `RemarkRehypeOptions` | - | Remark-rehype conversion options |
|
|
232
|
-
| `customElements` | `Record<string, Snippet<[ElementProps]>>` | - | Custom snippets for not handled nodes |
|
|
233
333
|
|
|
234
334
|
### Custom Component Props
|
|
235
335
|
|
|
236
|
-
**Every single markdown element** can be customized with Svelte snippets, giving you
|
|
336
|
+
**Every single markdown element** can be customized with Svelte snippets, giving you
|
|
337
|
+
complete control over styling and behavior:
|
|
338
|
+
|
|
339
|
+
Each snippet receives `{ children, token }` where `token` is a typed token object containing the parsed markdown token with its properties and children is a snippet to be rendered.
|
|
237
340
|
|
|
238
341
|
```svelte
|
|
239
342
|
<script>
|
|
@@ -244,36 +347,36 @@ This heading will use a custom component!`;
|
|
|
244
347
|
This heading uses a custom component with your design system!`;
|
|
245
348
|
</script>
|
|
246
349
|
|
|
247
|
-
{#snippet
|
|
350
|
+
{#snippet customHeading({ children, token })}
|
|
248
351
|
<h1
|
|
249
352
|
class="text-gradient mb-6 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-4xl font-bold text-transparent"
|
|
250
|
-
{...props}
|
|
353
|
+
{...token.props}
|
|
251
354
|
>
|
|
252
355
|
{@render children()}
|
|
253
356
|
</h1>
|
|
254
357
|
{/snippet}
|
|
255
358
|
|
|
256
|
-
{#snippet customCode({ children,
|
|
257
|
-
<code class="rounded bg-gray-100 px-2 py-1 font-mono text-sm dark:bg-gray-800" {...props}>
|
|
359
|
+
{#snippet customCode({ children, token })}
|
|
360
|
+
<code class="rounded bg-gray-100 px-2 py-1 font-mono text-sm dark:bg-gray-800" {...token.props}>
|
|
258
361
|
{@render children()}
|
|
259
362
|
</code>
|
|
260
363
|
{/snippet}
|
|
261
364
|
|
|
262
|
-
{#snippet customBlockquote({ children,
|
|
365
|
+
{#snippet customBlockquote({ children, token })}
|
|
263
366
|
<blockquote
|
|
264
367
|
class="border-l-4 border-blue-500 pl-4 text-gray-600 italic dark:text-gray-300"
|
|
265
|
-
{...props}
|
|
368
|
+
{...token.props}
|
|
266
369
|
>
|
|
267
370
|
{@render children()}
|
|
268
371
|
</blockquote>
|
|
269
372
|
{/snippet}
|
|
270
373
|
|
|
271
|
-
<Streamdown {content}
|
|
374
|
+
<Streamdown {content} heading={customHeading} code={customCode} blockquote={customBlockquote} />
|
|
272
375
|
```
|
|
273
376
|
|
|
274
377
|
#### All Available Customizable Elements:
|
|
275
378
|
|
|
276
|
-
**Text Elements**: `
|
|
379
|
+
**Text Elements**: `heading`, `p`, `strong`, `em`, `del`
|
|
277
380
|
|
|
278
381
|
**Links & Media**: `a`, `img`
|
|
279
382
|
|
|
@@ -285,95 +388,7 @@ This heading uses a custom component with your design system!`;
|
|
|
285
388
|
|
|
286
389
|
**Special Content**: `blockquote`, `hr`, `alert`, `mermaid`, `math`, `inlineMath`
|
|
287
390
|
|
|
288
|
-
**Note**: The above elements are **supported by Streamdown** and should be customized using individual props or the theme system.
|
|
289
|
-
|
|
290
|
-
Each snippet receives `{ children, ...props }` where `props` contains all element attributes and classes.
|
|
291
|
-
|
|
292
|
-
### Using `customElements` Record
|
|
293
|
-
|
|
294
|
-
The `customElements` prop is specifically for HTML elements that are **not handled by the library by default**. For elements already supported by Streamdown (like `h1`, `p`, `code`, etc.), use individual props or the theme system instead.
|
|
295
|
-
|
|
296
|
-
```svelte
|
|
297
|
-
<script>
|
|
298
|
-
import { Streamdown } from 'svelte-streamdown';
|
|
299
|
-
|
|
300
|
-
let content = `# Custom Elements Example
|
|
301
|
-
|
|
302
|
-
This content contains HTML elements not handled by Streamdown by default:
|
|
303
|
-
|
|
304
|
-
<div class="special">This is a custom div element</div>
|
|
305
|
-
|
|
306
|
-
<span class="highlight">This is a custom span element</span>
|
|
307
|
-
|
|
308
|
-
<section class="wrapper">
|
|
309
|
-
<article>This is a custom article inside a section</article>
|
|
310
|
-
</section>`;
|
|
311
|
-
|
|
312
|
-
// Define custom components for unsupported HTML elements
|
|
313
|
-
</script>
|
|
314
|
-
|
|
315
|
-
{#snippet customDiv({ children, props, className, node })}
|
|
316
|
-
<div class="rounded-lg border-2 border-blue-500 p-4 {className}" {...props}>
|
|
317
|
-
{@render children()}
|
|
318
|
-
</div>
|
|
319
|
-
{/snippet}
|
|
320
|
-
|
|
321
|
-
{#snippet customSpan({ children, props, className, node })}
|
|
322
|
-
<span class="rounded bg-yellow-200 px-2 py-1 {className}" {...props}>
|
|
323
|
-
{@render children()}
|
|
324
|
-
</span>
|
|
325
|
-
{/snippet}
|
|
326
|
-
|
|
327
|
-
{#snippet customSection({ children, props, className, node })}
|
|
328
|
-
<section class="my-8 rounded-xl bg-gray-50 p-6 {className}" {...props}>
|
|
329
|
-
{@render children()}
|
|
330
|
-
</section>
|
|
331
|
-
{/snippet}
|
|
332
|
-
|
|
333
|
-
{#snippet customArticle({ children, props, className, node })}
|
|
334
|
-
<article class="prose max-w-none {className}" {...props}>
|
|
335
|
-
{@render children()}
|
|
336
|
-
</article>
|
|
337
|
-
{/snippet}
|
|
338
|
-
|
|
339
|
-
<Streamdown
|
|
340
|
-
{content}
|
|
341
|
-
customElements={{
|
|
342
|
-
div: customDiv,
|
|
343
|
-
span: customSpan,
|
|
344
|
-
section: customSection,
|
|
345
|
-
article: customArticle
|
|
346
|
-
}}
|
|
347
|
-
/>
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Benefits of `customElements`
|
|
351
|
-
|
|
352
|
-
- **Handle Unsupported Elements**: Define components for HTML elements not built into Streamdown
|
|
353
|
-
- **Semantic HTML Support**: Use elements like `<section>`, `<article>`, `<aside>`, `<nav>`, etc.
|
|
354
|
-
- **Fallback Support**: Automatically handles unknown elements that would otherwise be ignored
|
|
355
|
-
- **Type Safety**: Full TypeScript support with `ElementProps` interface
|
|
356
|
-
|
|
357
|
-
### `customElements` vs Individual Props
|
|
358
|
-
|
|
359
|
-
Use the right approach for the right elements:
|
|
360
|
-
|
|
361
|
-
**Individual Props** (for supported Streamdown elements):
|
|
362
|
-
|
|
363
|
-
```svelte
|
|
364
|
-
<Streamdown {content} h1={customH1} p={customP} code={customCode} />
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
**CustomElements Record** (for unsupported HTML elements):
|
|
368
|
-
|
|
369
|
-
```svelte
|
|
370
|
-
<Streamdown
|
|
371
|
-
{content}
|
|
372
|
-
customElements={{ div: customDiv, span: customSpan, section: customSection }}
|
|
373
|
-
/>
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
**Note**: For supported elements (h1, p, code, etc.), use individual props or the theme system. For unsupported elements (div, span, section, etc.), use `customElements`.
|
|
391
|
+
**Note**: The above elements are **supported by Streamdown** and should be customized using individual props or the theme system.
|
|
377
392
|
|
|
378
393
|
## 🎨 Advanced Theming System
|
|
379
394
|
|
package/dist/Block.svelte
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
</script>
|
|
3
|
+
|
|
1
4
|
<script lang="ts">
|
|
2
5
|
import { parseIncompleteMarkdown } from './utils/parse-incomplete-markdown.js';
|
|
3
6
|
import Element from './Elements/Element.svelte';
|
|
4
|
-
import { lex, type StreamdownToken
|
|
7
|
+
import { lex, type StreamdownToken } from './marked/index.js';
|
|
5
8
|
|
|
6
9
|
let {
|
|
7
10
|
block
|
|
@@ -12,37 +15,8 @@
|
|
|
12
15
|
const tokens = $derived(lex(parseIncompleteMarkdown(block.trim())));
|
|
13
16
|
|
|
14
17
|
const getChildren = (token: StreamdownToken) => {
|
|
15
|
-
if (token
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (token.type === 'table') {
|
|
20
|
-
const headerRow = {
|
|
21
|
-
type: 'tableRow',
|
|
22
|
-
tokens: token.header.map((cell) => ({
|
|
23
|
-
type: 'tableCell',
|
|
24
|
-
...cell
|
|
25
|
-
})),
|
|
26
|
-
isHeader: true
|
|
27
|
-
} satisfies TableRow;
|
|
28
|
-
|
|
29
|
-
const rows = token.rows.reduce(
|
|
30
|
-
(acc, cells) => {
|
|
31
|
-
const row = {
|
|
32
|
-
type: 'tableRow',
|
|
33
|
-
tokens: cells.map((cell) => ({
|
|
34
|
-
type: 'tableCell',
|
|
35
|
-
...cell
|
|
36
|
-
})),
|
|
37
|
-
isHeader: false
|
|
38
|
-
} satisfies TableRow;
|
|
39
|
-
acc.push(row);
|
|
40
|
-
return acc;
|
|
41
|
-
},
|
|
42
|
-
[headerRow] as TableRow[]
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
return rows;
|
|
18
|
+
if (!token) {
|
|
19
|
+
return [];
|
|
46
20
|
}
|
|
47
21
|
const children =
|
|
48
22
|
'tokens' in token ? ((token.tokens || []) as StreamdownToken[]) : ([] as StreamdownToken[]);
|
|
@@ -63,15 +37,17 @@
|
|
|
63
37
|
|
|
64
38
|
{#snippet renderChildren(tokens: StreamdownToken[])}
|
|
65
39
|
{#each tokens as token}
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
40
|
+
{#if token}
|
|
41
|
+
{@const children = getChildren(token)}
|
|
42
|
+
{@const isTextOnlyNode = children.length === 0}
|
|
43
|
+
<Element {token}>
|
|
44
|
+
{#if isTextOnlyNode}
|
|
45
|
+
{'text' in token ? token.text : ''}
|
|
46
|
+
{:else}
|
|
47
|
+
{@render renderChildren(children)}
|
|
48
|
+
{/if}
|
|
49
|
+
</Element>
|
|
50
|
+
{/if}
|
|
75
51
|
{/each}
|
|
76
52
|
{/snippet}
|
|
77
53
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
/><path d="M12 17h.01" />`
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
import { useStreamdown } from '../Streamdown.
|
|
16
|
+
import { useStreamdown } from '../Streamdown.js';
|
|
17
17
|
import Slot from './Slot.svelte';
|
|
18
18
|
import type { AlertToken } from '../marked/index.js';
|
|
19
19
|
import type { Snippet } from 'svelte';
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
<Slot
|
|
36
36
|
props={{
|
|
37
37
|
children,
|
|
38
|
-
alertType,
|
|
39
38
|
token
|
|
40
39
|
}}
|
|
41
40
|
render={streamdown.snippets.alert}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { useStreamdown } from '../Streamdown.
|
|
2
|
+
import { useStreamdown } from '../Streamdown.js';
|
|
3
3
|
import { save } from '../utils/save.js';
|
|
4
4
|
import { useCopy } from '../utils/copy.svelte.js';
|
|
5
|
-
import { HighlighterManager, languageExtensionMap } from '../hightlighter.svelte.js';
|
|
5
|
+
import { HighlighterManager, languageExtensionMap } from '../utils/hightlighter.svelte.js';
|
|
6
6
|
import type { Tokens } from 'marked';
|
|
7
7
|
import type { Snippet } from 'svelte';
|
|
8
8
|
|
|
9
9
|
const {
|
|
10
|
-
token
|
|
11
|
-
children
|
|
10
|
+
token
|
|
12
11
|
}: {
|
|
13
12
|
token: Tokens.Code;
|
|
14
|
-
children: Snippet;
|
|
15
13
|
} = $props();
|
|
16
14
|
|
|
17
15
|
const streamdown = useStreamdown();
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { Tokens } from 'marked';
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
2
|
type $$ComponentProps = {
|
|
4
3
|
token: Tokens.Code;
|
|
5
|
-
children: Snippet;
|
|
6
4
|
};
|
|
7
5
|
declare const Code: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
6
|
type Code = ReturnType<typeof Code>;
|