@refrakt-md/svelte 0.9.1 → 0.9.2

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 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.1",
4
+ "version": "0.9.2",
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.1",
31
- "@refrakt-md/transform": "0.9.1",
32
- "@refrakt-md/types": "0.9.1"
30
+ "@refrakt-md/behaviors": "0.9.2",
31
+ "@refrakt-md/transform": "0.9.2",
32
+ "@refrakt-md/types": "0.9.2"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "svelte": "^5.0.0"
@@ -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
- <Component tag={node}>
67
- {#each node.children as child}
68
- <Renderer node={child} overrides={merged} />
69
- {/each}
70
- </Component>
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
- import Markdoc from '@markdoc/markdoc';
2
- import type { RenderableTreeNode, RenderableTreeNodes } from '@markdoc/markdoc';
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';