diff options
author | 2021-04-15 10:55:50 -0500 | |
---|---|---|
committer | 2021-04-15 10:55:50 -0500 | |
commit | 22ca9e0aacf26bf82aa5d0ddd6d1e1d495a1a945 (patch) | |
tree | db56218dd905aca708e39fae6c58d31f99df24dc /src/frontend/render/utils.ts | |
parent | ea33d7b2ab30f6434986bb0d8671e7f681076268 (diff) | |
download | astro-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.ts | 47 |
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); +}) |