import type { Root, RootContent } from "hast"; import { dom, styling, text, type Class, type Node } from "./dom.util"; import prose, { tag, a, blockquote, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "./proses"; import { heading } from "hast-util-heading"; import { headingRank } from "hast-util-heading-rank"; import { parseId } from "./general.util"; import { loading } from "#shared/proses"; export function renderMarkdown(markdown: Root, proses: Record): HTMLDivElement { return dom('div', {}, markdown.children.map(e => renderContent(e, proses))); } function renderContent(node: RootContent, proses: Record): Node { if(node.type === 'text' && node.value.length > 0 && node.value !== '\n') { return text(node.value); } else if(node.type === 'comment' && node.value.length > 0 && node.value !== '\n') { return undefined; } else if(node.type === 'element') { const children = node.children.map(e => renderContent(e, proses)), properties = { ...node.properties, class: node.properties.className as string | string[] }; if(node.tagName in proses) return prose(node.tagName, proses[node.tagName], children, properties); else return dom(node.tagName as keyof HTMLElementTagNameMap, properties, children); } return undefined; } export interface MDProperties { class?: Class; style?: string | Record } export default function(content: string, filter?: string, properties?: MDProperties): HTMLElement { const load = loading('normal'); useMarkdown().parse(content).then(data => { if(filter) { const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1; if(start !== -1) { let end = start; const rank = headingRank(data.children[start])!; while(end < data.children.length) { end++; if(heading(data.children[end]) && headingRank(data.children[end])! <= rank) break; } data = { ...data, children: data.children.slice(start, end) }; } } const el = renderMarkdown(data, { tag, a, blockquote, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th, }); if(properties) styling(el, properties); load.parentElement?.replaceChild(el, load); }); return load; }