amis2/examples/components/MdRenderer.jsx

261 lines
7.3 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 ReactDOM from 'react-dom';
2019-04-30 11:11:25 +08:00
import {render} from '../../src/index';
2019-06-11 17:00:02 +08:00
import axios from 'axios';
2019-04-30 11:11:25 +08:00
import TitleBar from '../../src/components/TitleBar';
import LazyComponent from '../../src/components/LazyComponent';
import Overlay from '../../src/components/Overlay';
import PopOver from '../../src/components/PopOver';
import NestedLinks from '../../src/components/AsideNav';
import {Portal} from 'react-overlays';
2020-07-23 20:31:51 +08:00
import classnames from 'classnames';
2019-04-30 11:11:25 +08:00
class CodePreview extends React.Component {
2019-11-07 10:41:14 +08:00
state = {
PlayGround: null
};
componentDidMount() {
require(['./Play'], component =>
this.setState({
PlayGround: component.default
}));
}
render() {
const {
container,
height,
setAsideFolded,
setHeaderVisible,
...rest
} = this.props;
const PlayGround = this.state.PlayGround;
// 不要放在 .markdown-body 下面,因为样式会干扰,复写又麻烦,所以通过 Overlay 渲染到同级
return (
<div>
<span style={{display: 'block', height: height}} ref="span" />
{PlayGround ? (
<Overlay
container={container}
target={() => this.refs.span}
placement="bottom"
show
>
<PopOver
2020-07-23 20:31:51 +08:00
offset={{x: 0, y: 50 - height}}
2019-11-07 10:41:14 +08:00
style={{height}}
2020-07-23 20:31:51 +08:00
className=":MDPreview-shcema-preview-popover"
2019-11-07 10:41:14 +08:00
>
2020-07-23 20:31:51 +08:00
<div className="MDPreview-schema-preview">
2019-11-07 10:41:14 +08:00
<PlayGround {...rest} vertical />
</div>
</PopOver>
</Overlay>
) : null}
</div>
);
}
2019-04-30 11:11:25 +08:00
}
function isActive(link, location) {
2019-11-07 10:41:14 +08:00
return !!(link.fullPath && link.fullPath === location.hash);
2019-04-30 11:11:25 +08:00
}
2020-07-23 20:31:51 +08:00
export default function (doc) {
2019-11-07 10:41:14 +08:00
return class extends React.Component {
static displayName = 'MarkdownRenderer';
ref = null;
doms = [];
constructor(props) {
super(props);
this.divRef = this.divRef.bind(this);
this.handleClick = this.handleClick.bind(this);
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
componentDidMount() {
this.renderSchema();
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
if (location.hash && location.hash.length > 1) {
// 禁用自动跳转
if (window.history && 'scrollRestoration' in window.history) {
window.history.scrollRestoration = 'manual';
2019-04-30 11:11:25 +08:00
}
2019-11-07 10:41:14 +08:00
const dom = document.querySelector(
`[name="${location.hash.substring(1)}"]`
);
dom && dom.scrollIntoView();
}
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
componentDidUpdate() {
this.renderSchema();
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
componentWillUnmount() {
this.doms.forEach(dom => ReactDOM.unmountComponentAtNode(dom));
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
handleClick(e) {
const href = e.target.getAttribute('href');
if (href && href[0] !== '#' && !/^http/.test(href)) {
e.preventDefault();
this.props.push(href);
}
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
divRef(ref) {
this.ref = ref;
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
if (ref) {
ref.innerHTML = doc.html;
}
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
renderSchema() {
const scripts = document.querySelectorAll('script[type="text/schema"]');
if (!scripts && !scripts.length) {
return;
}
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;
dom.setAttribute('class', 'doc-play-ground');
dom.setAttribute('style', `height: ${height}px;`);
script.parentNode.replaceChild(dom, script);
this.doms.push(dom);
ReactDOM.unstable_renderSubtreeIntoContainer(
this,
<LazyComponent
{...this.props}
container={() => ReactDOM.findDOMNode(this)}
height={height}
component={CodePreview}
code={script.innerText}
scope={props.scope}
unMountOnHidden
placeholder="加载中,请稍后。。。"
/>,
dom
);
}
}
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>
));
}
2019-11-07 10:41:14 +08:00
render() {
const {location} = this.props;
return (
2020-07-23 20:31:51 +08:00
<>
<div className="Doc-content">
{doc.title ? (
<div className="Doc-title">
<h1>{doc.title}</h1>
</div>
) : null}
<div className="markdown-body" ref={this.divRef}>
Doc
</div>
2019-11-07 10:41:14 +08:00
</div>
{doc.toc && doc.toc.children && doc.toc.children.length > 1 ? (
2020-07-23 20:31:51 +08:00
// <Portal container={() => document.querySelector('#asideInner')}>
// <NestedLinks
// navigations={[doc.toc]}
// renderLink={({
// link,
// active,
// toggleExpand,
// depth,
// classnames: cx
// }) => {
// let children = [];
// if (link.children) {
// children.push(
// <span
// key="expand-toggle"
// className={cx(`AsideNav-itemArrow`)}
// />
// );
// }
// link.badge &&
// children.push(
// <b
// key="badge"
// className={cx(
// 'AsideNav-itemBadge',
// link.badgeClassName || 'bg-info'
// )}
// >
// {link.badge}
// </b>
// );
// depth === 1 &&
// children.push(
// <i
// key="icon"
// className={cx('AsideNav-itemIcon fa fa-flag')}
// />
// );
// children.push(
// <span key="label" className={cx('AsideNav-itemLabel')}>
// {link.label}
// </span>
// );
// return link.fragment ? (
// <a href={`#${link.fragment}`}>{children}</a>
// ) : (
// <a
// onClick={link.children ? () => toggleExpand(link) : null}
// >
// {children}
// </a>
// );
// }}
// isActive={link => isActive(link, location)}
// />
// </Portal>
<div className="Doc-toc">
<div className="Doc-headingList">
{this.renderHeading(doc.toc.children)}
</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
}