import type { Root, RootContent } from "hast"; import { dom, styling, text, type Class, type Node } from "#shared/dom.util"; import prose, { a, blockquote, tag, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "#shared/proses"; import { heading } from "hast-util-heading"; import { headingRank } from "hast-util-heading-rank"; import { parseId } from "#shared/general.util"; import { async } from "#shared/components.util"; export function renderMarkdown(markdown: Root, proses: Record): HTMLDivElement { return dom('div', {}, markdown.children.map(e => renderContent(e, proses))); } export function renderMDAsText(markdown: string): string { return useMarkdown().text(markdown); } 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] ?? { class: '' }, children, properties); else return dom(node.tagName as keyof HTMLElementTagNameMap, properties, children); } return undefined; } export interface MDProperties { class?: Class; style?: string | Record; tags?: Record; } export function markdownReference(content: string, filter?: string, properties?: MDProperties) { const state = async('large', 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, { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th, ...properties?.tags }); if(properties) styling(el, properties); return el; })); return state; } export default function(content: string, filter?: string, properties?: MDProperties): HTMLElement { return markdownReference(content, filter, properties).current; }