mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-06-03 08:28:54 -04:00
71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
/*
|
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
import { HtmlToReact } from '../../common/html-to-react/html-to-react'
|
|
import type { MarkdownRendererExtension } from '../extensions/base/markdown-renderer-extension'
|
|
import { useCombinedNodePreprocessor } from './hooks/use-combined-node-preprocessor'
|
|
import { useConfiguredMarkdownIt } from './hooks/use-configured-markdown-it'
|
|
import { LineContentToLineIdMapper } from './utils/line-content-to-line-id-mapper'
|
|
import { NodeToReactTransformer } from './utils/node-to-react-transformer'
|
|
import type { ParserOptions } from '@hedgedoc/html-to-react'
|
|
import type DOMPurify from 'dompurify'
|
|
import React, { useMemo } from 'react'
|
|
|
|
export interface MarkdownToReactProps {
|
|
markdownContentLines: string[]
|
|
markdownRenderExtensions: MarkdownRendererExtension[]
|
|
newlinesAreBreaks?: boolean
|
|
allowHtml: boolean
|
|
}
|
|
|
|
/**
|
|
* Renders Markdown code.
|
|
*
|
|
* @param markdownContentLines The Markdown code lines that should be rendered
|
|
* @param additionalMarkdownExtensions A list of {@link MarkdownRendererExtension markdown extensions} that should be used
|
|
* @param newlinesAreBreaks Defines if the alternative break mode of markdown it should be used
|
|
* @param allowHtml Defines if html is allowed in markdown
|
|
*/
|
|
export const MarkdownToReact: React.FC<MarkdownToReactProps> = ({
|
|
markdownContentLines,
|
|
markdownRenderExtensions,
|
|
newlinesAreBreaks,
|
|
allowHtml
|
|
}) => {
|
|
const lineNumberMapper = useMemo(() => new LineContentToLineIdMapper(), [])
|
|
const nodeToReactTransformer = useMemo(() => new NodeToReactTransformer(), [])
|
|
|
|
useMemo(() => {
|
|
nodeToReactTransformer.setReplacers(markdownRenderExtensions.flatMap((extension) => extension.buildReplacers()))
|
|
}, [nodeToReactTransformer, markdownRenderExtensions])
|
|
|
|
useMemo(() => {
|
|
nodeToReactTransformer.setLineIds(lineNumberMapper.updateLineMapping(markdownContentLines))
|
|
}, [nodeToReactTransformer, lineNumberMapper, markdownContentLines])
|
|
|
|
const nodePreProcessor = useCombinedNodePreprocessor(markdownRenderExtensions)
|
|
const markdownIt = useConfiguredMarkdownIt(markdownRenderExtensions, allowHtml, newlinesAreBreaks ?? true)
|
|
|
|
const parserOptions: ParserOptions = useMemo(
|
|
() => ({
|
|
transform: (node, index) => nodeToReactTransformer.translateNodeToReactElement(node, index),
|
|
preprocessNodes: (document) => {
|
|
nodeToReactTransformer.resetReplacers()
|
|
return nodePreProcessor(document)
|
|
}
|
|
}),
|
|
[nodeToReactTransformer, nodePreProcessor]
|
|
)
|
|
|
|
const html = useMemo(() => markdownIt.render(markdownContentLines.join('\n')), [markdownContentLines, markdownIt])
|
|
const domPurifyConfig: DOMPurify.Config = useMemo(
|
|
() => ({
|
|
ADD_TAGS: markdownRenderExtensions.flatMap((extension) => extension.buildTagNameAllowList())
|
|
}),
|
|
[markdownRenderExtensions]
|
|
)
|
|
|
|
return <HtmlToReact htmlCode={html} parserOptions={parserOptions} domPurifyConfig={domPurifyConfig} />
|
|
}
|