diff options
author | 2023-03-21 08:17:20 -0400 | |
---|---|---|
committer | 2023-03-21 08:17:20 -0400 | |
commit | 86273b5881cc61ebee11d40280b4c0aba8f4bb2e (patch) | |
tree | e8846e535df75ddecfc83c092bf8cdff5144c5c3 /packages/integrations/markdoc/components/TreeNode.ts | |
parent | 6afb1efea8601cc2bfacec27a8d09c2533fb704a (diff) | |
download | astro-86273b5881cc61ebee11d40280b4c0aba8f4bb2e.tar.gz astro-86273b5881cc61ebee11d40280b4c0aba8f4bb2e.tar.zst astro-86273b5881cc61ebee11d40280b4c0aba8f4bb2e.zip |
[Markdoc] Refactor Renderer internals to use `renderComponent()` (#6607)
* wip: new TreeNode setup
* fix: pass children through `render`
* deps: remove stringify-attributes
* chore: changeset
---------
Co-authored-by: Nate Moore <nate@astro.build>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Diffstat (limited to 'packages/integrations/markdoc/components/TreeNode.ts')
-rw-r--r-- | packages/integrations/markdoc/components/TreeNode.ts | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/packages/integrations/markdoc/components/TreeNode.ts b/packages/integrations/markdoc/components/TreeNode.ts new file mode 100644 index 000000000..36fd63fee --- /dev/null +++ b/packages/integrations/markdoc/components/TreeNode.ts @@ -0,0 +1,81 @@ +import type { AstroInstance } from 'astro'; +import type { RenderableTreeNode } from '@markdoc/markdoc'; +import { createComponent, renderComponent, render } from 'astro/runtime/server/index.js'; +import Markdoc from '@markdoc/markdoc'; +import { MarkdocError, isCapitalized } from '../dist/utils.js'; + +export type TreeNode = + | { + type: 'text'; + content: string; + } + | { + type: 'component'; + component: AstroInstance['default']; + props: Record<string, any>; + children: TreeNode[]; + } + | { + type: 'element'; + tag: string; + attributes: Record<string, any>; + children: TreeNode[]; + }; + +export const ComponentNode = createComponent({ + factory(result: any, { treeNode }: { treeNode: TreeNode }) { + if (treeNode.type === 'text') return render`${treeNode.content}`; + const slots = { + default: () => render`${treeNode.children.map((child) => + renderComponent(result, 'ComponentNode', ComponentNode, { treeNode: child }) + )}`, + }; + if (treeNode.type === 'component') { + return renderComponent( + result, + treeNode.component.name, + treeNode.component, + treeNode.props, + slots + ); + } + return renderComponent(result, treeNode.tag, treeNode.tag, treeNode.attributes, slots); + }, + propagation: 'none', +}); + +export function createTreeNode( + node: RenderableTreeNode, + components: Record<string, AstroInstance['default']> = {} +): TreeNode { + if (typeof node === 'string' || typeof node === 'number') { + return { type: 'text', content: String(node) }; + } else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) { + return { type: 'text', content: '' }; + } + + if (node.name in components) { + const component = components[node.name]; + const props = node.attributes; + const children = node.children.map((child) => createTreeNode(child, components)); + + return { + type: 'component', + component, + props, + children, + }; + } else if (isCapitalized(node.name)) { + throw new MarkdocError({ + message: `Unable to render ${JSON.stringify(node.name)}.`, + hint: 'Did you add this to the "components" prop on your <Content /> component?', + }); + } else { + return { + type: 'element', + tag: node.name, + attributes: node.attributes, + children: node.children.map((child) => createTreeNode(child, components)), + }; + } +} |