From 7ff1018247d7589e5cca577199a5d052ec50dc1a Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 12 Dec 2022 11:05:02 +0100 Subject: [PATCH] fix(ContentRendererMarkdown): recreate vNodes in render function (#1734) --- .../components/ContentRendererMarkdown.vue | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/src/runtime/components/ContentRendererMarkdown.vue b/src/runtime/components/ContentRendererMarkdown.vue index 34a997470..091603cf4 100644 --- a/src/runtime/components/ContentRendererMarkdown.vue +++ b/src/runtime/components/ContentRendererMarkdown.vue @@ -10,7 +10,6 @@ import { useRuntimeConfig, useRoute } from '#app' import type { MarkdownNode, ParsedContentMeta } from '../types' type CreateElement = typeof h -type ContentVNode = VNode | string /** * Default slot name @@ -96,19 +95,11 @@ export default defineComponent({ // Resolve component if it's a Vue component component = resolveVueComponent(component as string) - // Process children - const children = (body.children || []).map(child => renderNode(child, h, meta)) - // Return Vue component return h( - component as any, - { - ...meta.component?.props, - ...this.$attrs - }, - { - default: createSlotFunction(children) - } + component as any, + { ...meta.component?.props, ...this.$attrs }, + renderSlots(body, h, meta, meta) ) } }) @@ -116,7 +107,7 @@ export default defineComponent({ /** * Render a markdown node */ -function renderNode (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentScope: any = {}): ContentVNode { +function renderNode (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentScope: any = {}): VNode { /** * Render Text node */ @@ -138,6 +129,7 @@ function renderNode (node: MarkdownNode, h: CreateElement, documentMeta: ParsedC } const props = propsToData(node, documentMeta) + return h( component as any, props, @@ -145,7 +137,7 @@ function renderNode (node: MarkdownNode, h: CreateElement, documentMeta: ParsedC ) } -function renderBinding (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentScope: any = {}): ContentVNode { +function renderBinding (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentScope: any = {}): VNode { const data = { ...parentScope, $route: () => useRoute(), @@ -171,31 +163,37 @@ function renderBinding (node: MarkdownNode, h: CreateElement, documentMeta: Pars /** * Create slots from `node` template children. */ -function renderSlots (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentProps: any): ContentVNode[] { +function renderSlots (node: MarkdownNode, h: CreateElement, documentMeta: ParsedContentMeta, parentProps: any): Record VNode[]> { const children: MarkdownNode[] = node.children || [] - const slots: Record> = children.reduce((data, node) => { + const slotNodes: Record = children.reduce((data, node) => { if (!isTemplate(node)) { - data[DEFAULT_SLOT].push(renderNode(node, h, documentMeta, parentProps)) - return data - } - - if (isDefaultTemplate(node)) { - data[DEFAULT_SLOT].push(...(node.children || []).map(child => renderNode(child, h, documentMeta, parentProps))) + data[DEFAULT_SLOT].push(node) return data } const slotName = getSlotName(node) - data[slotName] = (node.children || []).map(child => renderNode(child, h, documentMeta, parentProps)) + data[slotName] = data[slotName] || [] + // Append children to slot + data[slotName].push(...(node.children || [])) return data }, { [DEFAULT_SLOT]: [] as any[] }) - const slotEntries = Object.entries(slots).map(([name, vDom]) => ([name, createSlotFunction(vDom)])) + const slots = Object.entries(slotNodes).reduce((slots, [name, children]) => { + if (!children.length) { return slots } + + slots[name] = () => { + const vNodes = children.map(child => renderNode(child, h, documentMeta, parentProps)) + return mergeTextNodes(vNodes) + } + + return slots + }, {} as Record VNode[]>) - return Object.fromEntries(slotEntries) + return slots } /** @@ -344,20 +342,6 @@ function getSlotName (node: MarkdownNode) { return name || DEFAULT_SLOT } -/** - * Create a factory function if there is a node in the list - */ -function createSlotFunction (nodes: Array) { - return (nodes.length ? () => mergeTextNodes(nodes as VNode[]) : undefined) -} - -/** - * Check if node is root - */ -function isDefaultTemplate (node: MarkdownNode) { - return isTemplate(node) && getSlotName(node) === DEFAULT_SLOT -} - /** * Check if node is Vue template tag */