2019-07-14 09:51:35 +08:00

291 lines
9.1 KiB
JavaScript

import './css/BorderLayout.css';
import classNames from 'classnames/bind';
import PropTypes from 'prop-types';
/**
* 边框布局
* @author tengge / https://github.com/tengge1
*/
class BorderLayout extends React.Component {
constructor(props) {
super(props);
const children = this.props.children;
const north = children && children.filter(n => n.props.region === 'north')[0];
const south = children && children.filter(n => n.props.region === 'south')[0];
const west = children && children.filter(n => n.props.region === 'west')[0];
const east = children && children.filter(n => n.props.region === 'east')[0];
const center = children && children.filter(n => n.props.region === 'center')[0];
const northSplit = north && north.props.split || false;
const southSplit = south && south.props.split || false;
const westSplit = west && west.props.split || false;
const eastSplit = east && east.props.split || false;
const northCollapsed = north && north.props.collapsed || false;
const southCollapsed = south && south.props.collapsed || false;
const westCollapsed = west && west.props.collapsed || false;
const eastCollapsed = east && east.props.collapsed || false;
const onNorthToggle = north && north.props.onToggle || null;
const onSouthToggle = south && south.props.onToggle || null;
const onWestToggle = west && west.props.onToggle || null;
const onEastToggle = east && east.props.onToggle || null;
this.northRef = React.createRef();
this.southRef = React.createRef();
this.westRef = React.createRef();
this.eastRef = React.createRef();
this.state = {
northSplit, southSplit, westSplit, eastSplit,
northCollapsed, southCollapsed, westCollapsed, eastCollapsed,
};
this.handleNorthClick = this.handleNorthClick.bind(this, onNorthToggle);
this.handleSouthClick = this.handleSouthClick.bind(this, onSouthToggle);
this.handleWestClick = this.handleWestClick.bind(this, onWestToggle);
this.handleEastClick = this.handleEastClick.bind(this, onEastToggle);
this.handleTransitionEnd = this.handleTransitionEnd.bind(this, onNorthToggle, onSouthToggle, onWestToggle, onEastToggle);
}
handleNorthClick() {
if (!this.state.northSplit) {
return;
}
this.setState((state, props) => {
const collapsed = !state.northCollapsed;
const dom = this.northRef.current;
const height = dom.clientHeight;
if (collapsed) {
dom.style.marginTop = `-${height - 8}px`;
} else {
dom.style.marginTop = null;
}
return {
northCollapsed: collapsed,
};
});
}
handleSouthClick() {
if (!this.state.southSplit) {
return;
}
this.setState((state, props) => {
const collapsed = !state.southCollapsed;
const dom = this.southRef.current;
const height = dom.clientHeight;
if (collapsed) {
dom.style.marginBottom = `-${height - 8}px`;
} else {
dom.style.marginBottom = null;
}
return {
southCollapsed: collapsed,
};
});
}
handleWestClick() {
if (!this.state.westSplit) {
return;
}
const dom = this.westRef.current;
this.setState((state, props) => {
const collapsed = !state.westCollapsed;
const width = dom.clientWidth;
if (collapsed) {
dom.style.marginLeft = `-${width - 8}px`;
} else {
dom.style.marginLeft = null;
}
return {
westCollapsed: collapsed,
};
});
}
handleEastClick() {
if (!this.state.eastSplit) {
return;
}
this.setState((state, props) => {
const collapsed = !state.eastCollapsed;
const dom = this.eastRef.current;
const width = dom.clientWidth;
if (collapsed) {
dom.style.marginRight = `-${width - 8}px`;
} else {
dom.style.marginRight = null;
}
return {
eastCollapsed: collapsed,
};
});
}
handleTransitionEnd(onNorthToggle, onSouthToggle, onWestToggle, onEastToggle, event) {
const region = event.target.getAttribute('region');
switch (region) {
case 'north':
onNorthToggle && onNorthToggle(!this.state.northCollapsed);
break;
case 'south':
onSouthToggle && onSouthToggle(!this.state.southCollapsed);
break;
case 'west':
onWestToggle && onWestToggle(!this.state.westCollapsed);
break;
case 'east':
onEastToggle && onEastToggle(!this.state.eastCollapsed);
break;
}
}
render() {
const { className, style, children } = this.props;
let north = [], south = [], west = [], east = [], center = [], others = [];
children && children.forEach(n => {
switch (n.props.region) {
case 'north':
north.push(n);
break;
case 'south':
south.push(n);
break;
case 'west':
west.push(n);
break;
case 'east':
east.push(n);
break;
case 'center':
center.push(n);
break;
default:
others.push(n);
break;
}
});
if (center.length === 0) {
console.warn(`BorderLayout: center region is not defined.`);
}
// north region
const northRegion = north.length > 0 && (<div className={classNames('north',
this.state.northSplit && 'split',
this.state.northCollapsed && 'collapsed')}
region={'north'}
onTransitionEnd={this.handleTransitionEnd}
ref={this.northRef}>
<div className={'content'}>
{north}
</div>
{this.state.northSplit && <div className={'control'}>
<div className={'button'} onClick={this.handleNorthClick}></div>
</div>}
</div>);
// south region
const southRegion = south.length > 0 && (<div className={classNames('south',
this.state.northSplit && 'split',
this.state.southCollapsed && 'collapsed')}
region={'south'}
onTransitionEnd={this.handleTransitionEnd}
ref={this.southRef}>
{this.state.southSplit && <div className={'control'}>
<div className={'button'} onClick={this.handleSouthClick}></div>
</div>}
<div className={'content'}>
{south}
</div>
</div>);
// west region
const westRegion = west.length > 0 && (<div className={classNames('west',
this.state.westSplit && 'split',
this.state.westCollapsed && 'collapsed')}
region={'west'}
onTransitionEnd={this.handleTransitionEnd}
ref={this.westRef}>
<div className={'content'}>
{west}
</div>
{this.state.westSplit && <div className={'control'}>
<div className={'button'} onClick={this.handleWestClick}></div>
</div>}
</div>);
// east region
const eastRegion = east.length > 0 && (<div className={classNames('east',
this.state.eastSplit && 'split',
this.state.eastCollapsed && 'collapsed')}
region={'east'}
onTransitionEnd={this.handleTransitionEnd}
ref={this.eastRef}>
<div className={'control'}>
<div className={'button'} onClick={this.handleEastClick}></div>
</div>
<div className={'content'}>
{east}
</div>
</div>);
// center region
const centerRegion = center.length > 0 && (<div className={'center'}>
{center}
</div>);
const otherRegion = others.length > 0 && others;
return <div
className={classNames('BorderLayout', className)}
style={style}>
{northRegion}
<div className={'middle'}>
{westRegion}
{centerRegion}
{eastRegion}
</div>
{southRegion}
{otherRegion}
</div>;
}
}
BorderLayout.propTypes = {
className: PropTypes.string,
style: PropTypes.object,
children: PropTypes.node,
};
BorderLayout.defaultProps = {
className: null,
style: null,
children: null,
};
export default BorderLayout;