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';
|
2022-03-30 12:47:37 +08:00
|
|
|
|
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';
|
2022-06-20 21:11:06 +08:00
|
|
|
|
import {Overlay} from 'amis-core';
|
|
|
|
|
import {PopOver} from 'amis-core';
|
2020-07-23 20:31:51 +08:00
|
|
|
|
import classnames from 'classnames';
|
2022-02-10 13:50:12 +08:00
|
|
|
|
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
|
|
|
|
|
2022-03-30 12:47:37 +08:00
|
|
|
|
class CodePreview extends React.Component {
|
2019-11-07 10:41:14 +08:00
|
|
|
|
state = {
|
|
|
|
|
PlayGround: null
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render() {
|
2020-11-19 13:47:56 +08:00
|
|
|
|
const {container, setAsideFolded, setHeaderVisible, ...rest} = this.props;
|
|
|
|
|
|
2022-04-28 10:53:06 +08:00
|
|
|
|
return <Play {...rest} mini />;
|
2019-11-07 10:41:14 +08:00
|
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 12:47:37 +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;
|
2022-03-30 12:47:37 +08:00
|
|
|
|
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() {
|
2022-06-10 15:19:07 +08:00
|
|
|
|
// 立即 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
|
|
|
|
|
2022-03-30 12:47:37 +08:00
|
|
|
|
const root = createRoot(dom);
|
|
|
|
|
this.roots.push(root);
|
|
|
|
|
root.render(
|
2020-07-24 17:20:08 +08:00
|
|
|
|
<LazyComponent
|
|
|
|
|
{...this.props}
|
2022-03-30 12:47:37 +08:00
|
|
|
|
container={() => findDOMNode(this)}
|
2020-07-24 17:20:08 +08:00
|
|
|
|
component={CodePreview}
|
|
|
|
|
code={script.innerText}
|
|
|
|
|
scope={props.scope}
|
2020-12-20 15:17:58 +08:00
|
|
|
|
// unMountOnHidden
|
2020-12-09 00:35:24 +08:00
|
|
|
|
height={height}
|
2020-07-24 17:20:08 +08:00
|
|
|
|
placeholder="加载中,请稍后。。。"
|
2022-03-30 12:47:37 +08:00
|
|
|
|
/>
|
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;
|
|
|
|
|
}
|
2022-03-30 12:47:37 +08:00
|
|
|
|
const ns = getTheme(this.props.theme)?.classPrefix;
|
2020-12-16 16:17:24 +08:00
|
|
|
|
[].slice.call(htmlPreviews).forEach(dom => {
|
2022-03-30 12:47:37 +08:00
|
|
|
|
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
|
|
|
|
|
2022-03-30 12:47:37 +08:00
|
|
|
|
export default function (doc) {
|
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;
|
|
|
|
|
|
2021-11-11 15:20:35 +08:00
|
|
|
|
originTitle = document.title;
|
|
|
|
|
|
2020-10-22 20:04:52 +08:00
|
|
|
|
state = {
|
|
|
|
|
headingPopover: false
|
|
|
|
|
};
|
|
|
|
|
|
2022-03-30 12:47:37 +08:00
|
|
|
|
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>
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 12:47:37 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 15:20:35 +08:00
|
|
|
|
componentDidMount() {
|
|
|
|
|
if (doc.title) {
|
|
|
|
|
document.title = doc.title;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
document.title = this.originTitle;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-09 10:55:34 +08:00
|
|
|
|
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
|
2022-08-09 10:55:34 +08:00
|
|
|
|
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
|
|
|
|
}
|