@refrakt-md/svelte 0.9.1 → 0.9.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.
- package/package.json +4 -4
- package/src/Renderer.svelte +50 -5
- package/src/serialize.ts +2 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refrakt-md/svelte",
|
|
3
3
|
"description": "Svelte renderer for refrakt.md content",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@markdoc/markdoc": "0.4.0",
|
|
30
|
-
"@refrakt-md/behaviors": "0.9.
|
|
31
|
-
"@refrakt-md/transform": "0.9.
|
|
32
|
-
"@refrakt-md/types": "0.9.
|
|
30
|
+
"@refrakt-md/behaviors": "0.9.3",
|
|
31
|
+
"@refrakt-md/transform": "0.9.3",
|
|
32
|
+
"@refrakt-md/types": "0.9.3"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"svelte": "^5.0.0"
|
package/src/Renderer.svelte
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
+
import { createRawSnippet } from 'svelte';
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
6
8
|
import type { Component } from 'svelte';
|
|
7
9
|
import type { SerializedTag, RendererNode } from './types.js';
|
|
8
10
|
import { getComponent, getElementOverrides } from './context.js';
|
|
11
|
+
import { extractComponentInterface } from '@refrakt-md/transform';
|
|
9
12
|
import Renderer from './Renderer.svelte';
|
|
10
13
|
|
|
11
14
|
let { node, overrides }: { node: RendererNode; overrides?: Record<string, Component<any>> } = $props();
|
|
@@ -43,6 +46,47 @@
|
|
|
43
46
|
return `<${tag.name}${attrs}>${children}</${tag.name}>`;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
const VOID_ELEMENTS = new Set([
|
|
50
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
|
51
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr',
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
/** Render a RendererNode tree to an HTML string, handling codeblock/raw-html content */
|
|
55
|
+
function nodeToHtml(n: RendererNode): string {
|
|
56
|
+
if (n === null || n === undefined) return '';
|
|
57
|
+
if (typeof n === 'string') return escapeAttr(n);
|
|
58
|
+
if (typeof n === 'number') return String(n);
|
|
59
|
+
if (Array.isArray(n)) return n.map(nodeToHtml).join('');
|
|
60
|
+
if (!isTag(n)) return '';
|
|
61
|
+
if (n.name === 'svg') return svgToHtml(n);
|
|
62
|
+
|
|
63
|
+
const attrs = Object.entries(htmlAttrs(n.attributes))
|
|
64
|
+
.map(([k, v]) => ` ${k}="${escapeAttr(v)}"`)
|
|
65
|
+
.join('');
|
|
66
|
+
|
|
67
|
+
if (VOID_ELEMENTS.has(n.name)) return `<${n.name}${attrs}>`;
|
|
68
|
+
|
|
69
|
+
const isRaw = n.attributes?.['data-codeblock'] || n.attributes?.['data-raw-html'];
|
|
70
|
+
const inner = n.children.map(child => {
|
|
71
|
+
if (isRaw && typeof child === 'string') return child;
|
|
72
|
+
return nodeToHtml(child);
|
|
73
|
+
}).join('');
|
|
74
|
+
|
|
75
|
+
return `<${n.name}${attrs}>${inner}</${n.name}>`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Create a Svelte 5 snippet from an array of serialized nodes */
|
|
79
|
+
function createNodeSnippet(nodes: RendererNode[]): Snippet {
|
|
80
|
+
return createRawSnippet(() => ({
|
|
81
|
+
render: () => {
|
|
82
|
+
if (nodes.length === 1 && isTag(nodes[0])) {
|
|
83
|
+
return nodeToHtml(nodes[0]);
|
|
84
|
+
}
|
|
85
|
+
return `<div data-snippet-wrapper>${nodes.map(nodeToHtml).join('')}</div>`;
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
46
90
|
const globalOverrides = getElementOverrides();
|
|
47
91
|
const merged = $derived(overrides
|
|
48
92
|
? { ...globalOverrides, ...overrides }
|
|
@@ -63,11 +107,12 @@
|
|
|
63
107
|
{@const Component = node.attributes?.['data-rune'] ? getComponent(node.attributes['data-rune']) : undefined}
|
|
64
108
|
{@const ElementOverride = !Component && merged?.[node.name] ? merged[node.name] : undefined}
|
|
65
109
|
{#if Component}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
110
|
+
{@const iface = extractComponentInterface(node)}
|
|
111
|
+
{@const refSnippets = Object.fromEntries(
|
|
112
|
+
Object.entries(iface.refs).map(([name, tags]) => [name, createNodeSnippet(tags)])
|
|
113
|
+
)}
|
|
114
|
+
{@const childSnippet = iface.children.length > 0 ? createNodeSnippet(iface.children) : undefined}
|
|
115
|
+
<Component {...iface.properties} {...refSnippets} children={childSnippet} tag={node} />
|
|
71
116
|
{:else if ElementOverride}
|
|
72
117
|
<ElementOverride tag={node}>
|
|
73
118
|
{#each node.children as child}
|
package/src/serialize.ts
CHANGED
|
@@ -1,24 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { Tag } = Markdoc;
|
|
4
|
-
|
|
5
|
-
/** Convert a Markdoc Tag instance to a plain serializable object */
|
|
6
|
-
export function serialize(node: RenderableTreeNode): unknown {
|
|
7
|
-
if (node === null || node === undefined) return node;
|
|
8
|
-
if (typeof node === 'string' || typeof node === 'number') return node;
|
|
9
|
-
if (Tag.isTag(node)) {
|
|
10
|
-
return {
|
|
11
|
-
$$mdtype: 'Tag',
|
|
12
|
-
name: node.name,
|
|
13
|
-
attributes: node.attributes,
|
|
14
|
-
children: node.children.map(serialize),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
return node;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Convert a Markdoc tree (single node or array) to serializable POJOs */
|
|
21
|
-
export function serializeTree(tree: RenderableTreeNodes): unknown {
|
|
22
|
-
if (Array.isArray(tree)) return tree.map(serialize);
|
|
23
|
-
return serialize(tree);
|
|
24
|
-
}
|
|
1
|
+
// Re-export from @refrakt-md/transform for backward compatibility
|
|
2
|
+
export { serialize, serializeTree } from '@refrakt-md/transform';
|