amis2/examples/components/MdRenderer.jsx

386 lines
10 KiB
React
Raw Normal View History

2019-04-30 11:11:25 +08:00
/* eslint-disable no-unused-vars */
2019-06-11 17:00:02 +08:00
import React from 'react';
import {findDOMNode} from 'react-dom';
import {createRoot} from 'react-dom/client';
2022-06-01 15:06:00 +08:00
import {getTheme, render} from 'amis';
2022-06-01 21:35:49 +08:00
import {LazyComponent} from 'amis-core';
import {Overlay} from 'amis-core';
import {PopOver} from 'amis-core';
2020-07-23 20:31:51 +08:00
import classnames from 'classnames';
import {Link} from 'react-router-dom';
2020-12-09 00:35:24 +08:00
import Play from './Play';
2019-04-30 11:11:25 +08:00
class CodePreview extends React.Component {
2019-11-07 10:41:14 +08:00
state = {
PlayGround: null
};
render() {
const {container, setAsideFolded, setHeaderVisible, ...rest} = this.props;
return <Play {...rest} mini />;
2019-11-07 10:41:14 +08:00
}
2019-04-30 11:11:25 +08:00
}
function eachDom(dom, iterator) {
2020-12-01 11:43:30 +08:00
if (!dom) {
return;
}
iterator(dom);
if (dom.children && dom.children.length) {
[].slice.call(dom.children).forEach(dom => eachDom(dom, iterator));
}
}
2020-07-24 17:20:08 +08:00
class Preview extends React.Component {
static displayName = 'MarkdownRenderer';
ref = null;
roots = [];
2020-07-24 17:20:08 +08:00
constructor(props) {
super(props);
this.divRef = this.divRef.bind(this);
}
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
componentDidMount() {
this.renderSchema();
2020-12-01 11:43:30 +08:00
this.fixHtmlPreview();
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
if (location.hash && location.hash.length > 1) {
// 禁用自动跳转
if (window.history && 'scrollRestoration' in window.history) {
window.history.scrollRestoration = 'manual';
2019-11-07 10:41:14 +08:00
}
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
const dom = document.querySelector(
`[name="${location.hash.substring(1)}"]`
);
dom && dom.scrollIntoView();
2019-11-07 10:41:14 +08:00
}
2020-07-24 17:20:08 +08:00
}
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
componentDidUpdate() {
this.renderSchema();
2020-12-01 11:43:30 +08:00
this.fixHtmlPreview();
2020-07-24 17:20:08 +08:00
}
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
componentWillUnmount() {
// 立即 unmout 会报错
window.requestAnimationFrame(() => {
this.roots.forEach(root => root.unmount());
});
2020-07-24 17:20:08 +08:00
}
2019-04-30 11:11:25 +08:00
2020-07-24 17:20:08 +08:00
divRef(ref) {
this.ref = ref;
2019-11-07 10:41:14 +08:00
2020-07-24 17:20:08 +08:00
if (ref) {
ref.innerHTML = this.props.doc.html;
}
}
2019-11-07 10:41:14 +08:00
2020-07-24 17:20:08 +08:00
renderSchema() {
const scripts = document.querySelectorAll('script[type="text/schema"]');
if (!scripts && !scripts.length) {
return;
}
2019-11-07 10:41:14 +08:00
2020-07-24 17:20:08 +08:00
for (let i = 0, len = scripts.length; i < len; i++) {
let script = scripts[i];
let props = {};
[].slice.apply(script.attributes).forEach(item => {
props[item.name] = item.value;
});
let dom = document.createElement('div');
let height = props.height ? parseInt(props.height, 10) : 200;
2020-11-30 16:53:04 +08:00
if (this.props.viewMode === 'mobile') {
// 移动端下高度不能太低
if (height < 500) {
height = 500;
}
}
2020-07-24 17:20:08 +08:00
dom.setAttribute('class', 'doc-play-ground');
2020-12-09 00:35:24 +08:00
// dom.setAttribute('style', `min-height: ${height}px;`);
2020-11-30 16:53:04 +08:00
const origin = script.parentNode;
origin.parentNode.replaceChild(dom, origin);
2020-07-24 17:20:08 +08:00
const root = createRoot(dom);
this.roots.push(root);
root.render(
2020-07-24 17:20:08 +08:00
<LazyComponent
{...this.props}
container={() => findDOMNode(this)}
2020-07-24 17:20:08 +08:00
component={CodePreview}
code={script.innerText}
scope={props.scope}
// unMountOnHidden
2020-12-09 00:35:24 +08:00
height={height}
2020-07-24 17:20:08 +08:00
placeholder="加载中,请稍后。。。"
/>
2020-07-24 17:20:08 +08:00
);
2019-11-07 10:41:14 +08:00
}
2020-07-24 17:20:08 +08:00
}
2020-12-01 11:43:30 +08:00
fixHtmlPreview() {
const htmlPreviews = document.querySelectorAll('.amis-doc>.preview');
if (!htmlPreviews && !htmlPreviews.length) {
return;
}
const ns = getTheme(this.props.theme)?.classPrefix;
2020-12-16 16:17:24 +08:00
[].slice.call(htmlPreviews).forEach(dom => {
eachDom(dom, dom => {
2020-12-01 11:43:30 +08:00
if (typeof dom.className !== 'string') {
return;
}
dom.className = dom.className.replace(
/(^|\s)([A-Z])/g,
'$1' + ns + '$2'
);
});
});
}
2020-07-24 17:20:08 +08:00
render() {
return (
<div className="MDPreview">
2020-12-09 00:35:24 +08:00
<div className="markdown" ref={this.divRef}>
2020-07-24 17:20:08 +08:00
Doc
</div>
</div>
);
}
}
2019-11-07 10:41:14 +08:00
export default function (doc) {
chore: 开发环境切成 vite (#5677) * 尝试使用 vite 跑开发环境 * 尝试使用 vite 跑开发环境 * 尝试使用 vite 跑开发环境 * 尝试使用 vite 跑开发环境 * 样式文档调整 * 修复有多个 __inline 时的报错 * scirpt 调整 * feat:chart接入事件动作 (#5669) * chore: input-group 没有 name 不应该报 warning (#5667) * chore: 处理编译TS Warning,调整TableStore中label解析的顺序 (#5670) * feat: timeline时间轴支持自定义图标 (#5668) * fix:折叠器Collapse自定义图标&inputNumber对含后缀生效 * 修改 * 正则修改 * 正则修改 * 正则修改 * feat:将默认px替换为rem 2px===0.125rem * feat:timeline时间轴支持自定义图标 Co-authored-by: xujiahao01 <xujiahao01@baidu.com> * fix: 调整echarts-stat使用方式,兼容vite打包异步非esm模块 (#5672) * feat: chart 支持配置加载 geojson 及百度地图 (#5674) * feat: chart 支持配置 geoURL 及 geoName * 增加百度地图配置 * chore: 修复 coverage 运行报错 (#5678) * chore: coverage 执行换成 v8 解决内存问题 (#5679) * 尝试使用 vite 跑开发环境 * amis-formula 也添加 esm 模块 * 代码合并有问题,做些调整 Co-authored-by: hsm-lv <80095014+hsm-lv@users.noreply.github.com> Co-authored-by: 吴多益 <wuduoyi@baidu.com> Co-authored-by: RUNZE LU <36724300+lurunze1226@users.noreply.github.com> Co-authored-by: 徐佳豪 <1440054388@qq.com> Co-authored-by: xujiahao01 <xujiahao01@baidu.com> Co-authored-by: 刘丹 <365533093@qq.com>
2022-11-02 22:45:12 +08:00
doc = doc.default || doc;
2020-07-24 17:20:08 +08:00
return class extends React.Component {
2020-10-22 20:04:52 +08:00
popoverDom = null;
originTitle = document.title;
2020-10-22 20:04:52 +08:00
state = {
headingPopover: false
};
popoverRef = ref => {
2020-10-22 20:04:52 +08:00
this.popoverDom = ref;
};
2020-07-23 20:31:51 +08:00
renderHeading(children) {
return children.map((child, idx) => (
<div
key={`${child.fullPath}-${idx}`}
className={classnames('Doc-headingList-item', {
'is-active': this.props.location.hash === child.fullPath
})}
>
<a href={`#${child.fragment}`}>{child.label}</a>
{child.children && child.children.length
? this.renderHeading(child.children)
: null}
</div>
));
}
handlePopOverClick = e => {
2020-10-22 20:04:52 +08:00
this.setState({headingPopover: false});
e.stopPropagation();
2021-03-05 10:53:10 +08:00
// e.preventDefault();
2020-12-24 22:26:45 +08:00
};
2020-10-22 20:04:52 +08:00
renderHeadingPopover() {
return this.state.headingPopover ? (
<Overlay
target={this.popoverDom}
container={this.popoverDom}
rootClose={false}
placement="right-bottom-right-top"
show
>
<PopOver
classPrefix="cxd-"
className=":Doc-headingPopover"
onHide={() => this.setState({headingPopover: false})}
overlay
onClick={this.handlePopOverClick}
>
{this.renderHeading(doc.toc.children)}
</PopOver>
</Overlay>
) : null;
}
componentDidMount() {
if (doc.title) {
document.title = doc.title;
}
}
componentWillUnmount() {
document.title = this.originTitle;
}
pathJoin(...parts) {
const separator = '/';
const normalizedParts = parts
.filter(
part =>
part != null &&
(typeof part === 'string' || typeof part === 'number')
)
.map((item, index, arr) => {
let part = `${item}`;
// 去除首个元素之外的"/"前缀
if (index > 0) {
part = part.replace(/^[\/]+/, '');
}
// 去除中间元素的"/"后缀,最后一个元素的多个"/"后缀改为1个
return index < arr.length - 1
? part.replace(/[\/]+$/, '')
: part.replace(/[\/]+$/, '/');
});
return normalizedParts.join(separator);
}
getDocEditLink() {
const {ContextPath} = this.props;
const basePath = 'https://github.com/baidu/amis/edit/master';
try {
const [urlPath, locale, moduleName, relativePath] = location.pathname
.replace(ContextPath, '')
.match(/^\/(zh-CN)\/(docs|components|style|)(([\/]?[\w-]+)*)/);
if (moduleName === 'docs') {
return this.pathJoin(
basePath,
`/docs/${locale}/`,
`${relativePath}.md`
);
} else if (
moduleName === 'style' &&
!/style\/(index|css-vars|responsive-design|state)$/.test(urlPath)
) {
const fileName = location.pathname.split('/')?.slice(-1)?.[0];
return this.pathJoin(
basePath,
`/packages/amis-ui/scss/helper`,
relativePath.replace(fileName, `/_${fileName}.scss`)
);
} else {
return this.pathJoin(
basePath,
`/docs/${locale}/${moduleName}`,
`/${relativePath}.md`
);
}
} catch (error) {
return this.pathJoin(basePath, 'docs');
}
}
2019-11-07 10:41:14 +08:00
render() {
2020-07-31 13:18:44 +08:00
const {prevDoc, nextDoc, ContextPath} = this.props;
2020-07-28 14:55:49 +08:00
2019-11-07 10:41:14 +08:00
return (
2020-07-23 20:31:51 +08:00
<>
<div className="Doc-content">
{doc.title ? (
<div className="Doc-title">
<h1>{doc.title}</h1>
2020-10-22 20:04:52 +08:00
{doc?.toc.children?.length ? (
<div
ref={this.popoverRef}
onClick={e =>
this.setState({
headingPopover: !this.state.headingPopover
})
}
className="Doc-headingPopBtn visible-xs"
>
<i className="fa fa-align-right"></i>
{this.renderHeadingPopover()}
</div>
) : null}
2020-07-23 20:31:51 +08:00
</div>
) : null}
2020-07-28 14:55:49 +08:00
2020-07-24 17:20:08 +08:00
<Preview {...this.props} doc={doc} />
2020-07-28 14:55:49 +08:00
<div className="Doc-footer">
<div className="Doc-navLinks">
{prevDoc ? (
2020-07-31 13:07:34 +08:00
<Link
className="Doc-navLinks--prev"
to={`${ContextPath}${prevDoc.path}`}
>
2020-07-28 14:55:49 +08:00
<div className="Doc-navLinks-icon">
<i className="iconfont icon-arrow-left"></i>
</div>
<div className="Doc-navLinks-body text-right">
<div className="Doc-navLinks-subtitle">
上一篇 - {prevDoc.group || '其他'}
</div>
<div className="Doc-navLinks-title">{prevDoc.label} </div>
</div>
</Link>
) : null}
{nextDoc ? (
2020-07-31 13:07:34 +08:00
<Link
className="Doc-navLinks--next"
to={`${ContextPath}${nextDoc.path}`}
>
2020-07-28 14:55:49 +08:00
<div className="Doc-navLinks-body">
<div className="Doc-navLinks-subtitle">
下一篇 - {nextDoc.group || '其他'}
</div>
<div className="Doc-navLinks-title">{nextDoc.label}</div>
</div>
<div className="Doc-navLinks-icon">
<i className="iconfont icon-arrow-right"></i>
</div>
</Link>
) : null}
</div>
2020-07-31 15:35:17 +08:00
<div className="Doc-footer-divider"></div>
<div className="Doc-footer-fixme">
文档有误
<a
href={this.getDocEditLink()}
rel="noopener noreferrer"
2020-07-31 15:35:17 +08:00
target="_blank"
>
Github 上编辑此页
</a>
</div>
2020-07-28 14:55:49 +08:00
</div>
2019-11-07 10:41:14 +08:00
</div>
2020-08-06 15:18:45 +08:00
{doc.toc && doc.toc.children && doc.toc.children.length > 0 ? (
2020-08-05 13:22:14 +08:00
<div className="Doc-toc hidden-xs hidden-sm">
2020-07-29 15:33:25 +08:00
<div>
<div className="Doc-headingList">
{this.renderHeading(doc.toc.children)}
</div>
2020-07-23 20:31:51 +08:00
</div>
</div>
2019-11-07 10:41:14 +08:00
) : null}
2020-07-23 20:31:51 +08:00
</>
2019-11-07 10:41:14 +08:00
);
2019-04-30 11:11:25 +08:00
}
2019-11-07 10:41:14 +08:00
};
2019-04-30 11:11:25 +08:00
}