@humanspeak/svelte-markdown 0.5.3

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.
Files changed (55) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +263 -0
  3. package/dist/Parser.svelte +99 -0
  4. package/dist/Parser.svelte.d.ts +13 -0
  5. package/dist/SvelteMarkdown.svelte +63 -0
  6. package/dist/SvelteMarkdown.svelte.d.ts +11 -0
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.js +2 -0
  9. package/dist/renderers/Blockquote.svelte +10 -0
  10. package/dist/renderers/Blockquote.svelte.d.ts +5 -0
  11. package/dist/renderers/Br.svelte +10 -0
  12. package/dist/renderers/Br.svelte.d.ts +5 -0
  13. package/dist/renderers/Code.svelte +9 -0
  14. package/dist/renderers/Code.svelte.d.ts +5 -0
  15. package/dist/renderers/Codespan.svelte +9 -0
  16. package/dist/renderers/Codespan.svelte.d.ts +4 -0
  17. package/dist/renderers/Del.svelte +10 -0
  18. package/dist/renderers/Del.svelte.d.ts +5 -0
  19. package/dist/renderers/Em.svelte +11 -0
  20. package/dist/renderers/Em.svelte.d.ts +5 -0
  21. package/dist/renderers/Heading.svelte +33 -0
  22. package/dist/renderers/Heading.svelte.d.ts +11 -0
  23. package/dist/renderers/Hr.svelte +1 -0
  24. package/dist/renderers/Hr.svelte.d.ts +26 -0
  25. package/dist/renderers/Html.svelte +9 -0
  26. package/dist/renderers/Html.svelte.d.ts +4 -0
  27. package/dist/renderers/Image.svelte +11 -0
  28. package/dist/renderers/Image.svelte.d.ts +6 -0
  29. package/dist/renderers/Link.svelte +12 -0
  30. package/dist/renderers/Link.svelte.d.ts +7 -0
  31. package/dist/renderers/List.svelte +17 -0
  32. package/dist/renderers/List.svelte.d.ts +7 -0
  33. package/dist/renderers/ListItem.svelte +10 -0
  34. package/dist/renderers/ListItem.svelte.d.ts +5 -0
  35. package/dist/renderers/Paragraph.svelte +10 -0
  36. package/dist/renderers/Paragraph.svelte.d.ts +5 -0
  37. package/dist/renderers/Strong.svelte +10 -0
  38. package/dist/renderers/Strong.svelte.d.ts +5 -0
  39. package/dist/renderers/Table.svelte +10 -0
  40. package/dist/renderers/Table.svelte.d.ts +5 -0
  41. package/dist/renderers/TableBody.svelte +10 -0
  42. package/dist/renderers/TableBody.svelte.d.ts +5 -0
  43. package/dist/renderers/TableCell.svelte +17 -0
  44. package/dist/renderers/TableCell.svelte.d.ts +7 -0
  45. package/dist/renderers/TableHead.svelte +10 -0
  46. package/dist/renderers/TableHead.svelte.d.ts +5 -0
  47. package/dist/renderers/TableRow.svelte +10 -0
  48. package/dist/renderers/TableRow.svelte.d.ts +5 -0
  49. package/dist/renderers/Text.svelte +11 -0
  50. package/dist/renderers/Text.svelte.d.ts +5 -0
  51. package/dist/renderers/index.d.ts +21 -0
  52. package/dist/renderers/index.js +21 -0
  53. package/dist/utils/markdown-parser.d.ts +27 -0
  54. package/dist/utils/markdown-parser.js +47 -0
  55. package/package.json +89 -0
package/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2024 Humanspeak, Inc.
2
+
3
+ Copyright (c) 2020-2024 Pablo Berganza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # Svelte Markdown
2
+
3
+ A markdown parser that renders into Svelte Components. Inspired by [ReactMarkdown](https://github.com/remarkjs/react-markdown).
4
+
5
+ ## Installation
6
+
7
+ You can install it with
8
+
9
+ ```console
10
+ npm i -S @humanspeak/svelte-markdown
11
+ ```
12
+
13
+ If you use npm or if you prefer yarn
14
+
15
+ ```console
16
+ yarn add @humanspeak/svelte-markdown
17
+ ```
18
+
19
+ If you're using Sapper you might need to install it as a dev dependency.
20
+
21
+ ## Usage
22
+
23
+ ```html
24
+ <script>
25
+ import SvelteMarkdown from '@humanspeak/svelte-markdown'
26
+ const source = `
27
+ # This is a header
28
+
29
+ This is a paragraph.
30
+
31
+ * This is a list
32
+ * With two items
33
+ 1. And a sublist
34
+ 2. That is ordered
35
+ * With another
36
+ * Sublist inside
37
+
38
+ | And this is | A table |
39
+ |-------------|---------|
40
+ | With two | columns |`
41
+ </script>
42
+
43
+ <SvelteMarkdown {source} />
44
+ ```
45
+
46
+ This would render something like
47
+
48
+ ```html
49
+ <h1>This is a header</h1>
50
+ <p>This is a paragraph.</p>
51
+ <ul>
52
+ <li>This is a list</li>
53
+ <li>
54
+ With two items
55
+ <ol start="1">
56
+ <li>And a sublist</li>
57
+ <li>
58
+ That is ordered
59
+ <ul>
60
+ <li>With another</li>
61
+ <li>Sublist inside</li>
62
+ </ul>
63
+ </li>
64
+ </ol>
65
+ </li>
66
+ </ul>
67
+ <table>
68
+ <thead>
69
+ <tr>
70
+ <th>And this is</th>
71
+ <th>A table</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody>
75
+ <tr>
76
+ <td>With two</td>
77
+ <td>columns</td>
78
+ </tr>
79
+ </tbody>
80
+ </table>
81
+ ```
82
+
83
+ ## Note
84
+
85
+ Just like with React Markdown, this package doesn't use `{@html ...}` unless you need to render HTML.
86
+
87
+ ## Props
88
+
89
+ The SvelteMarkdown component accepts the following props:
90
+
91
+ - `source` - _string_ or _array_ The Markdown source to be parsed, or an array of tokens to be rendered directly.
92
+ - `renderers` - _object (optional)_ An object where the keys represent a node type and the value is a Svelte component. This object will be merged with the default renderers. For now you can check how the default renderers are written in the source code at `src/renderers`.
93
+ - `options` - _object (optional)_ An object containing [options for Marked](https://marked.js.org/using_advanced#options)
94
+
95
+ ## Renderers
96
+
97
+ To create custom renderer for an element, you can create a Svelte component with the default props ([you can check them here](https://marked.js.org/using_pro#renderer)), for example:
98
+
99
+ _`ImageComponent.svelte`_
100
+
101
+ ```svelte
102
+ <script>
103
+ export let href = ''
104
+ export let title = undefined
105
+ export let text = ''
106
+ </script>
107
+
108
+ <img src={href} {title} alt={text} />
109
+ ```
110
+
111
+ So you can import the component and pass to the `renderers` props:
112
+
113
+ ```svelte
114
+ <script>
115
+ import SvelteMarkdown from '@humanspeak/svelte-markdown'
116
+ import ImageComponent from './renderers/ImageComponent.svelte'
117
+ export let content
118
+ </script>
119
+
120
+ <SvelteMarkdown source={content} renderers={{ image: ImageComponent }} />
121
+ ```
122
+
123
+ ## Rendering From Tokens
124
+
125
+ For greater flexibility, an array of tokens may be given as `source`, in which case parsing is skipped and the tokens will be rendered directly. This alows you to generate and transform the tokens freely beforehand. Example:
126
+
127
+ ```html
128
+ <script>
129
+ import SvelteMarkdown from '@humanspeak/svelte-markdown'
130
+ import { marked } from 'marked'
131
+
132
+ const tokens = marked.lexer('this is an **example**')
133
+
134
+ marked.walkTokens(tokens, (token) => {
135
+ if (token.type == 'strong') token.type = 'em'
136
+ token.raw = token.raw.toUpperCase()
137
+ })
138
+ </script>
139
+
140
+ <SvelteMarkdown source="{tokens}" />
141
+ ```
142
+
143
+ This will render the following:
144
+
145
+ ```html
146
+ <p>THIS IS AN <em>EXAMPLE</em></p>
147
+ ```
148
+
149
+ ## Events
150
+
151
+ A `parsed` event will be fired when the final tokens have been calculated, allowing you to access the raw token array if needed for things like generating Table of Contents from headings.
152
+
153
+ ```html
154
+ <script>
155
+ import SvelteMarkdown from '@humanspeak/svelte-markdown'
156
+
157
+ const source = `# This is a header`
158
+
159
+ const handleParsed = async (parsedTokens: Token[] | TokensList) => {
160
+ console.log('displaying tokens', parsedTokens)
161
+ }
162
+ </script>
163
+
164
+ <SvelteMarkdown {source} parsed="{handleParsed}"></SvelteMarkdown>
165
+ ```
166
+
167
+ ## Available renderers
168
+
169
+ These would be the property names expected by the `renderers` option.
170
+
171
+ - `text` - Text rendered inside of other elements, such as paragraphs
172
+ - `paragraph` - Paragraph (`<p>`)
173
+ - `em` - Emphasis (`<em>`)
174
+ - `strong` - Strong/bold (`<strong>`)
175
+ - `hr` - Horizontal rule / thematic break (`<hr>`)
176
+ - `blockquote` - Block quote (`<blockquote>`)
177
+ - `del` - Deleted/strike-through (`<del>`)
178
+ - `link` - Link (`<a>`)
179
+ - `image` - Image (`<img>`)
180
+ - `table` - Table (`<table>`)
181
+ - `tablehead` - Table head (`<thead>`)
182
+ - `tablebody` - Table body (`<tbody>`)
183
+ - `tablerow` - Table row (`<tr>`)
184
+ - `tablecell` - Table cell (`<td>`/`<th>`)
185
+ - `list` - List (`<ul>`/`<ol>`)
186
+ - `listitem` - List item (`<li>`)
187
+ - `heading` - Heading (`<h1>`-`<h6>`)
188
+ - `codespan` - Inline code (`<code>`)
189
+ - `code` - Block of code (`<pre><code>`)
190
+ - `html` - HTML node
191
+
192
+ ### Optional List Renderers
193
+
194
+ For fine detail styling of lists, it can be useful to differentiate between ordered and un-ordered lists.
195
+ If either key is missing, the default `listitem` will be used. There are two
196
+ optional keys in the `renderers` option which can provide this:
197
+
198
+ - `orderedlistitem` - A list item appearing inside an ordered list
199
+ - `unorderedlistitem` A list item appearing inside an un-ordered list
200
+
201
+ As an example, if we have an `orderedlistitem`:
202
+
203
+ ```html
204
+ <style>
205
+ li::marker {
206
+ color: blue;
207
+ }
208
+ </style>
209
+
210
+ <li><slot></slot></li>
211
+ ```
212
+
213
+ Then numbers at the start of ordered list items would be colored blue. Bullets at the start of unordered list items
214
+ would remain the default text color.
215
+
216
+ ### Inline Markdown
217
+
218
+ To use [inline markdown](https://marked.js.org/using_advanced#inline), you can assign the prop `isInline` to the component.
219
+
220
+ ```html
221
+ <SvelteMarkdown {source} isInline />
222
+ ```
223
+
224
+ ## HTML rendering
225
+
226
+ While the most common flavours of markdown let you use HTML in markdown paragraphs, due to how Svelte handles plain HTML it is currently not possible to do this with this package. A paragraph must be either _all_ HTML or _all_ markdown.
227
+
228
+ ```markdown
229
+ This is a **markdown** paragraph.
230
+
231
+ <p>This is an <strong>HTML</strong> paragraph</p>
232
+ ```
233
+
234
+ Note that the HTML paragraph must be enclosed within `<p>` tags.
235
+
236
+ ## Developing
237
+
238
+ Some tests have been added to the `tests` folder. You can clone this repo and create another svelte app and link it to this repo to try modifying it.
239
+
240
+ You can clone this repo and do the following:
241
+
242
+ ```console
243
+ yarn
244
+ yarn link
245
+ yarn dev
246
+ ```
247
+
248
+ This will watch all changes and make the project linkable. Now on the app you created you can link it with:
249
+
250
+ ```console
251
+ yarn link @humanspeak/svelte-markdown
252
+ ```
253
+
254
+ And then import it like in the example above.
255
+
256
+ As of now the only external dependency of this project is `marked`.
257
+
258
+ ## Related
259
+
260
+ - [ReactMarkdown](https://github.com/remarkjs/react-markdown) - React library to render markdown using React components. Inspiration for this library.
261
+ - [Svelte](https://svelte.dev) - JavaScript front-end framework.
262
+ - [Marked](https://marked.js.org/) - Markdown parser
263
+ - [Original](https://github.com/pablo-abc/svelte-markdown) - Original component
@@ -0,0 +1,99 @@
1
+ <script lang="ts">
2
+ import Parser from './Parser.svelte'
3
+ import type { Renderers, Token, TokensList, Tokens } from './utils/markdown-parser.js'
4
+
5
+ interface Props {
6
+ type?: string
7
+ tokens?: Token[] | TokensList
8
+ header?: Tokens.TableCell[]
9
+ rows?: Tokens.TableCell[][]
10
+ ordered?: boolean
11
+ renderers: Renderers
12
+ }
13
+
14
+ const {
15
+ type = undefined,
16
+ tokens = undefined,
17
+ header = undefined,
18
+ rows = undefined,
19
+ ordered = false,
20
+ renderers,
21
+ ...rest
22
+ }: Props & {
23
+ [key: string]: unknown
24
+ } = $props()
25
+ </script>
26
+
27
+ {#if !type}
28
+ {#if tokens}
29
+ {#each tokens as token}
30
+ {@const { text, raw, ...parserRest } = rest}
31
+ <Parser {...token} {renderers} {...parserRest} />
32
+ {/each}
33
+ {/if}
34
+ {:else if type in renderers}
35
+ {#if type === 'table'}
36
+ <renderers.table {...rest}>
37
+ <renderers.tablehead {...rest}>
38
+ <renderers.tablerow {...rest}>
39
+ {#each header ?? [] as headerItem, i}
40
+ <renderers.tablecell
41
+ header={true}
42
+ align={rest.align[i] || 'center'}
43
+ {...rest}
44
+ >
45
+ <Parser tokens={headerItem.tokens} {renderers} />
46
+ </renderers.tablecell>
47
+ {/each}
48
+ </renderers.tablerow>
49
+ </renderers.tablehead>
50
+ <renderers.tablebody {...rest}>
51
+ {#each rows ?? [] as row}
52
+ <renderers.tablerow {...rest}>
53
+ {#each row ?? [] as cells, i}
54
+ <renderers.tablecell
55
+ header={false}
56
+ align={rest.align[i] || 'center'}
57
+ {...rest}
58
+ >
59
+ <Parser tokens={cells.tokens} {renderers} />
60
+ </renderers.tablecell>
61
+ {/each}
62
+ </renderers.tablerow>
63
+ {/each}
64
+ </renderers.tablebody>
65
+ </renderers.table>
66
+ {:else if type === 'list'}
67
+ {#if ordered}
68
+ <renderers.list {ordered} {...rest}>
69
+ {@const items = rest.items as Props[]}
70
+ {#each items as item}
71
+ {@const SvelteComponent = renderers.orderedlistitem || renderers.listitem}
72
+ <SvelteComponent {...item}>
73
+ <Parser tokens={item.tokens} {renderers} />
74
+ </SvelteComponent>
75
+ {/each}
76
+ </renderers.list>
77
+ {:else}
78
+ <renderers.list {ordered} {...rest}>
79
+ {@const items = rest.items as Props[]}
80
+ {#each items as item}
81
+ {@const SvelteComponent_1 = renderers.unorderedlistitem || renderers.listitem}
82
+ <SvelteComponent_1 {...item} {...rest}>
83
+ <Parser tokens={item.tokens} {renderers} {...rest} />
84
+ </SvelteComponent_1>
85
+ {/each}
86
+ </renderers.list>
87
+ {/if}
88
+ {:else}
89
+ {@const SvelteComponent_2 = renderers[type]}
90
+ <SvelteComponent_2 {...rest}>
91
+ {#if tokens}
92
+ {@const { text, raw, ...parserRest } = rest}
93
+ <Parser {tokens} {renderers} {...parserRest} />
94
+ {:else}
95
+ {rest.raw}
96
+ {/if}
97
+ </SvelteComponent_2>
98
+ {/if}
99
+ {/if}
@@ -0,0 +1,13 @@
1
+ import Parser from './Parser.svelte';
2
+ import type { Renderers, Token, TokensList, Tokens } from './utils/markdown-parser.js';
3
+ declare const Parser: import("svelte").Component<{
4
+ type?: string;
5
+ tokens?: Token[] | TokensList;
6
+ header?: Tokens.TableCell[];
7
+ rows?: Tokens.TableCell[][];
8
+ ordered?: boolean;
9
+ renderers: Renderers;
10
+ } & {
11
+ [key: string]: unknown;
12
+ }, {}, "">;
13
+ export default Parser;
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import {
3
+ Lexer,
4
+ defaultOptions,
5
+ defaultRenderers,
6
+ Slugger,
7
+ type Token,
8
+ type TokensList,
9
+ type SvelteMarkdownOptions
10
+ } from './utils/markdown-parser.js'
11
+ import Parser from './Parser.svelte'
12
+
13
+ interface Props {
14
+ source: Token[] | string
15
+ renderers?: object
16
+ options?: SvelteMarkdownOptions
17
+ isInline?: boolean
18
+ parsed?: (tokens: Token[] | TokensList) => void // eslint-disable-line no-unused-vars
19
+ }
20
+
21
+ const {
22
+ source = [],
23
+ renderers = {},
24
+ options = {} as SvelteMarkdownOptions,
25
+ isInline = false,
26
+ parsed = () => {},
27
+ ...rest
28
+ }: Props & {
29
+ [key: string]: unknown
30
+ } = $props()
31
+ let tokens: Token[] | TokensList | undefined = $state<Token[] | TokensList | undefined>(
32
+ undefined
33
+ )
34
+ let lexer: Lexer | undefined = undefined
35
+
36
+ const slugger = source ? new Slugger() : undefined
37
+ const combinedOptions = { ...defaultOptions, ...options }
38
+
39
+ $effect.pre(() => {
40
+ if (Array.isArray(source)) {
41
+ tokens = source as Token[]
42
+ } else {
43
+ lexer = new Lexer(combinedOptions)
44
+ tokens = isInline ? lexer.inlineTokens(source as string) : lexer.lex(source as string)
45
+ }
46
+ })
47
+ $effect(() => {
48
+ if (tokens) parsed($state.snapshot(tokens))
49
+ })
50
+
51
+ const combinedRenderers = {
52
+ ...defaultRenderers,
53
+ ...renderers
54
+ }
55
+ </script>
56
+
57
+ <Parser
58
+ {tokens}
59
+ {...rest}
60
+ options={combinedOptions}
61
+ slug={(val: string): string => (slugger ? slugger.slug(val) : '')}
62
+ renderers={combinedRenderers}
63
+ />
@@ -0,0 +1,11 @@
1
+ import { type Token, type TokensList, type SvelteMarkdownOptions } from './utils/markdown-parser.js';
2
+ declare const SvelteMarkdown: import("svelte").Component<{
3
+ source: Token[] | string;
4
+ renderers?: object;
5
+ options?: SvelteMarkdownOptions;
6
+ isInline?: boolean;
7
+ parsed?: (tokens: Token[] | TokensList) => void;
8
+ } & {
9
+ [key: string]: unknown;
10
+ }, {}, "">;
11
+ export default SvelteMarkdown;
@@ -0,0 +1,4 @@
1
+ import type { SvelteMarkdownOptions, Token, TokensList } from './utils/markdown-parser.js';
2
+ import SvelteMarkdown from './SvelteMarkdown.svelte';
3
+ export default SvelteMarkdown;
4
+ export type { SvelteMarkdownOptions, Token, TokensList };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import SvelteMarkdown from './SvelteMarkdown.svelte';
2
+ export default SvelteMarkdown;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <blockquote>{@render children?.()}</blockquote>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Blockquote: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Blockquote;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <br />{@render children?.()}
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Br: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Br;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ lang: string
4
+ text: string
5
+ }
6
+ const { lang, text }: Props = $props()
7
+ </script>
8
+
9
+ <pre class={lang}><code>{text}</code></pre>
@@ -0,0 +1,5 @@
1
+ declare const Code: import("svelte").Component<{
2
+ lang: string;
3
+ text: string;
4
+ }, {}, "">;
5
+ export default Code;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ raw: string
4
+ }
5
+
6
+ const { raw }: Props = $props()
7
+ </script>
8
+
9
+ <code>{raw.replace(/`/g, '')}</code>
@@ -0,0 +1,4 @@
1
+ declare const Codespan: import("svelte").Component<{
2
+ raw: string;
3
+ }, {}, "">;
4
+ export default Codespan;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <del>{@render children?.()}</del>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Del: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Del;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+
8
+ const { children }: Props = $props()
9
+ </script>
10
+
11
+ <em>{@render children?.()}</em>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Em: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Em;
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+ import type { SvelteMarkdownOptions } from '../utils/markdown-parser.js'
4
+
5
+ interface Props {
6
+ depth: number
7
+ raw: string
8
+ text: string
9
+ options: SvelteMarkdownOptions
10
+ slug: (val: string) => string // eslint-disable-line no-unused-vars
11
+ children?: Snippet
12
+ }
13
+
14
+ const { depth, raw, text, options, slug, children }: Props = $props()
15
+
16
+ const id = $derived(options.headerIds ? options.headerPrefix + slug(text) : undefined)
17
+ </script>
18
+
19
+ {#if depth === 1}
20
+ <h1 {id}>{@render children?.()}</h1>
21
+ {:else if depth === 2}
22
+ <h2 {id}>{@render children?.()}</h2>
23
+ {:else if depth === 3}
24
+ <h3 {id}>{@render children?.()}</h3>
25
+ {:else if depth === 4}
26
+ <h4 {id}>{@render children?.()}</h4>
27
+ {:else if depth === 5}
28
+ <h5 {id}>{@render children?.()}</h5>
29
+ {:else if depth === 6}
30
+ <h6 {id}>{@render children?.()}</h6>
31
+ {:else}
32
+ {raw}
33
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { SvelteMarkdownOptions } from '../utils/markdown-parser.js';
3
+ declare const Heading: import("svelte").Component<{
4
+ depth: number;
5
+ raw: string;
6
+ text: string;
7
+ options: SvelteMarkdownOptions;
8
+ slug: (val: string) => string;
9
+ children?: Snippet;
10
+ }, {}, "">;
11
+ export default Heading;
@@ -0,0 +1 @@
1
+ <hr />
@@ -0,0 +1,26 @@
1
+ export default Hr;
2
+ type Hr = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const Hr: $$__sveltets_2_IsomorphicComponent<{
10
+ [x: string]: never;
11
+ }, {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}, {}, string>;
14
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
+ $$bindings?: Bindings;
17
+ } & Exports;
18
+ (internal: unknown, props: {
19
+ $$events?: Events;
20
+ $$slots?: Slots;
21
+ }): Exports & {
22
+ $set?: any;
23
+ $on?: any;
24
+ };
25
+ z_$$bindings?: Bindings;
26
+ }
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ text: string
4
+ }
5
+
6
+ const { text }: Props = $props()
7
+ </script>
8
+
9
+ {@html text}
@@ -0,0 +1,4 @@
1
+ declare const Html: import("svelte").Component<{
2
+ text: string;
3
+ }, {}, "">;
4
+ export default Html;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ href?: string
4
+ title?: string
5
+ text?: string
6
+ }
7
+
8
+ const { href = '', title = undefined, text = '' }: Props = $props()
9
+ </script>
10
+
11
+ <img src={href} {title} alt={text} />
@@ -0,0 +1,6 @@
1
+ declare const Image: import("svelte").Component<{
2
+ href?: string;
3
+ title?: string;
4
+ text?: string;
5
+ }, {}, "">;
6
+ export default Image;
@@ -0,0 +1,12 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ href?: string
6
+ title?: string
7
+ children?: Snippet
8
+ }
9
+ const { href = '', title = undefined, children }: Props = $props()
10
+ </script>
11
+
12
+ <a {href} {title}>{@render children?.()}</a>
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Link: import("svelte").Component<{
3
+ href?: string;
4
+ title?: string;
5
+ children?: Snippet;
6
+ }, {}, "">;
7
+ export default Link;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ ordered?: boolean
6
+ start?: number
7
+ children?: Snippet
8
+ }
9
+
10
+ const { ordered = false, start = 1, children }: Props = $props()
11
+ </script>
12
+
13
+ {#if ordered}
14
+ <ol {start}>{@render children?.()}</ol>
15
+ {:else}
16
+ <ul>{@render children?.()}</ul>
17
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const List: import("svelte").Component<{
3
+ ordered?: boolean;
4
+ start?: number;
5
+ children?: Snippet;
6
+ }, {}, "">;
7
+ export default List;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <li>{@render children?.()}</li>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const ListItem: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default ListItem;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <p>{@render children?.()}</p>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Paragraph: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Paragraph;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <strong>{@render children?.()}</strong>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Strong: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Strong;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <table>{@render children?.()}</table>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const Table: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Table;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <tbody>{@render children?.()}</tbody>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const TableBody: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default TableBody;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ header: boolean
6
+ align: 'left' | 'center' | 'right' | 'justify' | 'char' | null | undefined
7
+ children?: Snippet
8
+ }
9
+
10
+ const { header, align, children }: Props = $props()
11
+ </script>
12
+
13
+ {#if header}
14
+ <th {align}>{@render children?.()}</th>
15
+ {:else}
16
+ <td {align}>{@render children?.()}</td>
17
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const TableCell: import("svelte").Component<{
3
+ header: boolean;
4
+ align: "left" | "center" | "right" | "justify" | "char" | null | undefined;
5
+ children?: Snippet;
6
+ }, {}, "">;
7
+ export default TableCell;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <thead>{@render children?.()}</thead>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const TableHead: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default TableHead;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+ const { children }: Props = $props()
8
+ </script>
9
+
10
+ <tr>{@render children?.()}</tr>
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare const TableRow: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default TableRow;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { type Snippet } from 'svelte'
3
+
4
+ interface Props {
5
+ children?: Snippet
6
+ }
7
+
8
+ const { children }: Props = $props()
9
+ </script>
10
+
11
+ {@render children?.()}
@@ -0,0 +1,5 @@
1
+ import { type Snippet } from 'svelte';
2
+ declare const Text: import("svelte").Component<{
3
+ children?: Snippet;
4
+ }, {}, "">;
5
+ export default Text;
@@ -0,0 +1,21 @@
1
+ export { default as Blockquote } from './Blockquote.svelte';
2
+ export { default as Br } from './Br.svelte';
3
+ export { default as Code } from './Code.svelte';
4
+ export { default as Codespan } from './Codespan.svelte';
5
+ export { default as Del } from './Del.svelte';
6
+ export { default as Em } from './Em.svelte';
7
+ export { default as Heading } from './Heading.svelte';
8
+ export { default as Hr } from './Hr.svelte';
9
+ export { default as Html } from './Html.svelte';
10
+ export { default as Image } from './Image.svelte';
11
+ export { default as Link } from './Link.svelte';
12
+ export { default as List } from './List.svelte';
13
+ export { default as ListItem } from './ListItem.svelte';
14
+ export { default as Paragraph } from './Paragraph.svelte';
15
+ export { default as Strong } from './Strong.svelte';
16
+ export { default as Table } from './Table.svelte';
17
+ export { default as TableBody } from './TableBody.svelte';
18
+ export { default as TableCell } from './TableCell.svelte';
19
+ export { default as TableHead } from './TableHead.svelte';
20
+ export { default as TableRow } from './TableRow.svelte';
21
+ export { default as Text } from './Text.svelte';
@@ -0,0 +1,21 @@
1
+ export { default as Blockquote } from './Blockquote.svelte';
2
+ export { default as Br } from './Br.svelte';
3
+ export { default as Code } from './Code.svelte';
4
+ export { default as Codespan } from './Codespan.svelte';
5
+ export { default as Del } from './Del.svelte';
6
+ export { default as Em } from './Em.svelte';
7
+ export { default as Heading } from './Heading.svelte';
8
+ export { default as Hr } from './Hr.svelte';
9
+ export { default as Html } from './Html.svelte';
10
+ export { default as Image } from './Image.svelte';
11
+ export { default as Link } from './Link.svelte';
12
+ export { default as List } from './List.svelte';
13
+ export { default as ListItem } from './ListItem.svelte';
14
+ export { default as Paragraph } from './Paragraph.svelte';
15
+ export { default as Strong } from './Strong.svelte';
16
+ export { default as Table } from './Table.svelte';
17
+ export { default as TableBody } from './TableBody.svelte';
18
+ export { default as TableCell } from './TableCell.svelte';
19
+ export { default as TableHead } from './TableHead.svelte';
20
+ export { default as TableRow } from './TableRow.svelte';
21
+ export { default as Text } from './Text.svelte';
@@ -0,0 +1,27 @@
1
+ export { default as Slugger } from 'github-slugger';
2
+ export { Lexer, type Token, type Tokens, type TokensList } from 'marked';
3
+ import type { Component } from 'svelte';
4
+ export interface Renderers {
5
+ [key: string]: Component<any> | null;
6
+ }
7
+ export declare const defaultRenderers: Renderers;
8
+ export type SvelteMarkdownOptions = {
9
+ baseUrl: string | null;
10
+ breaks: boolean;
11
+ gfm: boolean;
12
+ headerIds: boolean;
13
+ headerPrefix: string;
14
+ highlight: null;
15
+ langPrefix: string;
16
+ mangle: boolean;
17
+ pedantic: boolean;
18
+ renderer: null;
19
+ sanitize: boolean;
20
+ sanitizer: null;
21
+ silent: boolean;
22
+ smartLists: boolean;
23
+ smartypants: boolean;
24
+ tokenizer: null;
25
+ xhtml: boolean;
26
+ };
27
+ export declare const defaultOptions: SvelteMarkdownOptions;
@@ -0,0 +1,47 @@
1
+ export { default as Slugger } from 'github-slugger';
2
+ export { Lexer } from 'marked';
3
+ import { Blockquote, Br, Code, Codespan, Del, Em, Heading, Hr, Html, Image, Link, List, ListItem, Paragraph, Strong, Table, TableBody, TableCell, TableHead, TableRow, Text } from '../renderers/index.js';
4
+ export const defaultRenderers = {
5
+ heading: Heading,
6
+ paragraph: Paragraph,
7
+ text: Text,
8
+ image: Image,
9
+ link: Link,
10
+ em: Em,
11
+ strong: Strong,
12
+ codespan: Codespan,
13
+ del: Del,
14
+ table: Table,
15
+ tablehead: TableHead,
16
+ tablebody: TableBody,
17
+ tablerow: TableRow,
18
+ tablecell: TableCell,
19
+ list: List,
20
+ orderedlistitem: null,
21
+ unorderedlistitem: null,
22
+ listitem: ListItem,
23
+ hr: Hr,
24
+ html: Html,
25
+ blockquote: Blockquote,
26
+ code: Code,
27
+ br: Br
28
+ };
29
+ export const defaultOptions = {
30
+ baseUrl: null,
31
+ breaks: false,
32
+ gfm: true,
33
+ headerIds: true,
34
+ headerPrefix: '',
35
+ highlight: null,
36
+ langPrefix: 'language-',
37
+ mangle: true,
38
+ pedantic: false,
39
+ renderer: null,
40
+ sanitize: false,
41
+ sanitizer: null,
42
+ silent: false,
43
+ smartLists: false,
44
+ smartypants: false,
45
+ tokenizer: null,
46
+ xhtml: false
47
+ };
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@humanspeak/svelte-markdown",
3
+ "description": "A markdown renderer for Svelte",
4
+ "version": "0.5.3",
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build && npm run package",
8
+ "preview": "vite preview",
9
+ "package": "svelte-kit sync && svelte-package && publint",
10
+ "prepublishOnly": "npm run package",
11
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
+ "test": "vitest run --coverage",
14
+ "test:only": "vitest run",
15
+ "test:watch": "vitest",
16
+ "lint": "prettier --check . && eslint .",
17
+ "lint:fix": "npm run format && eslint . --fix",
18
+ "format": "prettier --write ."
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/humanspeak/svelte-markdown.git"
23
+ },
24
+ "author": "Humanspeak, Inc.",
25
+ "license": "MIT",
26
+ "bugs": {
27
+ "url": "https://github.com/humanspeak/svelte-markdown/issues"
28
+ },
29
+ "homepage": "https://github.com/humanspeak/svelte-markdown",
30
+ "files": [
31
+ "dist",
32
+ "!dist/**/*.test.*",
33
+ "!dist/**/*.spec.*"
34
+ ],
35
+ "sideEffects": [
36
+ "**/*.css"
37
+ ],
38
+ "svelte": "./dist/index.js",
39
+ "types": "./dist/index.d.ts",
40
+ "type": "module",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.ts",
44
+ "svelte": "./dist/index.js"
45
+ }
46
+ },
47
+ "peerDependencies": {
48
+ "svelte": "^5.0.0"
49
+ },
50
+ "dependencies": {
51
+ "marked": "^14.1.3"
52
+ },
53
+ "devDependencies": {
54
+ "@eslint/eslintrc": "^3.1.0",
55
+ "@eslint/js": "^9.13.0",
56
+ "@sveltejs/kit": "^2.7.3",
57
+ "@sveltejs/package": "^2.3.7",
58
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
59
+ "@testing-library/jest-dom": "^6.6.2",
60
+ "@testing-library/svelte": "^5.2.4",
61
+ "@testing-library/user-event": "^14.5.2",
62
+ "@types/node": "^22.8.4",
63
+ "@typescript-eslint/eslint-plugin": "^8.12.2",
64
+ "@typescript-eslint/parser": "^8.12.2",
65
+ "@vitest/coverage-v8": "^2.1.4",
66
+ "eslint": "^9.13.0",
67
+ "eslint-config-prettier": "^9.1.0",
68
+ "eslint-plugin-svelte": "^2.46.0",
69
+ "github-slugger": "^2.0.0",
70
+ "globals": "^15.11.0",
71
+ "jsdom": "^25.0.1",
72
+ "prettier": "^3.3.3",
73
+ "prettier-plugin-organize-imports": "^4.1.0",
74
+ "prettier-plugin-svelte": "^3.2.7",
75
+ "prettier-plugin-tailwindcss": "^0.6.8",
76
+ "publint": "^0.2.12",
77
+ "svelte": "^5.1.4",
78
+ "svelte-check": "^4.0.5",
79
+ "typescript": "^5.6.3",
80
+ "@sveltejs/adapter-auto": "^3.3.1",
81
+ "vite": "^5.4.10",
82
+ "vitest": "^2.1.4"
83
+ },
84
+ "overrides": {
85
+ "@sveltejs/kit": {
86
+ "cookie": "^0.7.0"
87
+ }
88
+ }
89
+ }