summaryrefslogtreecommitdiff
path: root/src/frontend/render/utils.ts
diff options
context:
space:
mode:
authorGravatar Nate Moore <natemoo-re@users.noreply.github.com> 2021-04-15 10:55:50 -0500
committerGravatar GitHub <noreply@github.com> 2021-04-15 10:55:50 -0500
commit22ca9e0aacf26bf82aa5d0ddd6d1e1d495a1a945 (patch)
treedb56218dd905aca708e39fae6c58d31f99df24dc /src/frontend/render/utils.ts
parentea33d7b2ab30f6434986bb0d8671e7f681076268 (diff)
downloadastro-22ca9e0aacf26bf82aa5d0ddd6d1e1d495a1a945.tar.gz
astro-22ca9e0aacf26bf82aa5d0ddd6d1e1d495a1a945.tar.zst
astro-22ca9e0aacf26bf82aa5d0ddd6d1e1d495a1a945.zip
Support children inside of components (#72)
* chore(examples): add kitchen-sink * feat: support children in rendered components * feat: add support for rendering children in Svelte * fix: cleanup p/react fragment children * chore: add @ts-nocheck to svelte files * chore: update lockfiles * fix: types * feat: memoize frontend/renderer/utils * fix: disable eslint for compiled SvelteWrapper * fix: add missing dep Co-authored-by: Nate Moore <nate@skypack.dev>
Diffstat (limited to 'src/frontend/render/utils.ts')
-rw-r--r--src/frontend/render/utils.ts47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/frontend/render/utils.ts b/src/frontend/render/utils.ts
new file mode 100644
index 000000000..7001a7f95
--- /dev/null
+++ b/src/frontend/render/utils.ts
@@ -0,0 +1,47 @@
+import unified from 'unified';
+import parse from 'rehype-parse';
+import toH from 'hast-to-hyperscript';
+import { ComponentRenderer } from '../../@types/renderer';
+import moize from 'moize';
+
+/** @internal */
+function childrenToTree(children: string[]) {
+ return children.map(child => (unified().use(parse, { fragment: true }).parse(child) as any).children.pop());
+}
+
+/**
+ * Converts an HTML fragment string into vnodes for rendering via provided framework
+ * @param h framework's `createElement` function
+ * @param children the HTML string children
+ */
+export const childrenToVnodes = moize.deep(function childrenToVnodes(h: any, children: string[]) {
+ const tree = childrenToTree(children);
+ const vnodes = tree.map(subtree => toH(h, subtree));
+ return vnodes;
+})
+
+/**
+ * Converts an HTML fragment string into h function calls as a string
+ * @param h framework's `createElement` function
+ * @param children the HTML string children
+ */
+export const childrenToH = moize.deep(function childrenToH(renderer: ComponentRenderer<any>, children: string[]): any {
+ if (!renderer.jsxPragma) return;
+ const tree = childrenToTree(children);
+ const innerH = (name: any, attrs: Record<string, any>|null = null, _children: string[]|null = null) => {
+ const vnode = renderer.jsxPragma?.(name, attrs, _children);
+ const childStr = _children ? `, [${_children.map(child => serializeChild(child)).join(',')}]` : '';
+ /* fix(react): avoid hard-coding keys into the serialized tree */
+ if (attrs && attrs.key) attrs.key = undefined;
+ const __SERIALIZED = `${renderer.jsxPragmaName}("${name}", ${attrs ? JSON.stringify(attrs) : 'null'}${childStr})` as string;
+ return { ...vnode, __SERIALIZED }
+ }
+ const serializeChild = (child: unknown) => {
+ if (typeof child === 'string') return `\`${child}\``;
+ if (typeof child === 'number' || typeof child === 'boolean') return `${child}`;
+ if (child === null) return `null`;
+ if ((child as any).__SERIALIZED) return (child as any).__SERIALIZED;
+ return innerH(child).__SERIALIZED;
+ }
+ return tree.map(subtree => toH(innerH, subtree).__SERIALIZED);
+})