import { ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; import { Collapse, Popover } from 'antd'; import { get, sortBy, uniq } from 'lodash-es'; import React from 'react'; import Markdown from 'react-markdown'; import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import { useSnapshot } from 'valtio'; import { store } from '../../model'; import { CollapsedIcon } from '../../pages/Example/components/CollapsedIcon'; import { ExampleTopic } from '../../types'; import { getDemoInfo } from '../CodeRunner/utils'; import styles from './index.module.less'; const { Panel } = Collapse; type APIProps = { isPlayground?: boolean; topic: string; example: string; demo: string; exampleTopics: ExampleTopic[]; language?: string; }; const EMPTY = /^\s*$/; /** * API 预览 */ export const API = ({ exampleTopics, topic, example, demo, language = 'zh' }: APIProps) => { const state = useSnapshot(store); const demoInfo = getDemoInfo(exampleTopics, topic, example, demo); const APIContent = get(demoInfo, ['api', language]); /** 从 MD 中解析出层级数据(eg: #、##、###)作为折叠分组条件 */ const findHashTag = (lines: string[]) => { const tagLines = lines.filter((line) => line.startsWith('#')); const tagReg = /^#+/g; const tagLengths = tagLines.map((line) => line.match(tagReg)[0].length); return sortBy(uniq(tagLengths)); }; const getRegex = (tagLength: number) => { return new RegExp(`^${new Array(tagLength).fill('#').join('')}\\s+([^\\n]*)`); }; /** 根据正则将内容切片 */ const setIndexTag = (lines: string[], regex: RegExp, start = 0) => { const result = []; lines.forEach((line, index) => { if (regex.exec(line)) { const header = regex.exec(line)[1]; result.push({ header, start: index + start, maxEndIndex: start + lines.length, }); } }); return result; }; /** 从 MD 中解析出嵌套结构, 最多支持 2 层 */ const getNestedDOM = (lines: string[]) => { const tags = findHashTag(lines); let result = setIndexTag(lines, getRegex(tags[0])); if (tags.length > 2) { result = result.map((item, index) => { const { start } = item; return { ...item, children: setIndexTag(lines.slice(start + 1, result[index + 1]?.start), getRegex(tags[1]), start + 1), }; }); } return result; }; const MarkdownComponent = ({ content }) => ( ; }, }} > {content} ); /** 将扁平状态的 MD 解析为嵌套结构 */ const renderNestedDom = (content: string) => { if (!content) { return null; } const lines = content.split('\n'); const result = getNestedDOM(lines); /** 避免无标题的情况内容丢失,内层嵌套的不做处理(不合理) */ const minStart = get(result, [0, 'start']); return ( {minStart > 0 && (
)} {result.map((item, index) => { const { start, header, children = [] } = item; const end = index === result.length - 1 ? lines.length : result[index + 1].start; return ( {header}} key={header}> {children.length > 0 ? ( {children.map((nestedItem, nestedIndex) => { const { start: nestedStart, header: nestedHeader, maxEndIndex } = nestedItem; const nestEnd = nestedIndex === children.length - 1 ? maxEndIndex : children[nestedIndex + 1].start; return ( {nestedHeader}} key={nestedHeader} > ); })} ) : ( )} ); })}
); }; return (

API

{ store.apiContainerWidth += 100; }} /> { if (state.apiContainerWidth > 150) { store.apiContainerWidth -= 100; } }} />
{ store.showAPI = show; }} style={{ left: 0, top: 0, }} />
{!EMPTY.test(APIContent) ? ( renderNestedDom(APIContent) ) : (

404

Sorry, the API you visited does not exist.

)}
); };