import { makeAbsoluteUrl } from '@/utils/url-helper'; import React, { useCallback, useMemo } from 'react'; import { isValidStr, parseUrlStr, useTranslation } from 'tailchat-shared'; import { Loadable } from '../Loadable'; import { Image } from 'tailchat-design'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; import './render.less'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const ReactMarkdown = Loadable(() => import('react-markdown')); export const Markdown: React.FC<{ raw: string; baseUrl?: string; }> = React.memo(({ raw, baseUrl }) => { const { t } = useTranslation(); const transformUrl = useCallback( (url: string) => { url = parseUrlStr(url); if (!isValidStr(baseUrl)) { return url; } return new URL(url, makeAbsoluteUrl(baseUrl)).href; }, [baseUrl] ); /** * Markdown自定义渲染组件 */ const components = useMemo< React.ComponentProps['components'] >( () => ({ img: (props) => ( ), svg: () =>
not support svg
, iframe: (props) => { let src = props.src; if (!src) { return
; } if (!src.startsWith('http')) { return
only support http source
; } if (src && src.includes('?')) { src += '&autoplay=0'; // make sure media autoplay is false } return [/md] // return ( transformUrl(src)} transformLinkUri={(href) => transformUrl(href)} remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]} linkTarget="_blank" skipHtml={true} components={components} > {raw} ); }); Markdown.displayName = 'Markdown';