Merge branch 'master' into performance-enhancements

This commit is contained in:
Chi Vinh Le
2017-11-30 22:23:11 +01:00
98 changed files with 1559 additions and 889 deletions
@@ -0,0 +1,133 @@
import React from 'react';
import ExtendableTabPanel from '../components/ExtendableTabPanel';
import {connect} from 'react-redux';
import {TabPane} from 'coral-ui';
import ExtendableTab from '../components/ExtendableTab';
import {getShallowChanges} from 'coral-framework/utils';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';
class ExtendableTabPanelContainer extends React.Component {
static contextTypes = {
plugins: PropTypes.object,
};
componentDidMount() {
this.handleFallback();
}
componentWillReceiveProps(next) {
this.handleFallback(next);
}
shouldComponentUpdate(next) {
// Prevent Slot from rerendering when only reduxState has changed and
// it does not result in a change of slot children.
const changes = getShallowChanges(this.props, next);
if (changes.length === 1 && changes[0] === 'reduxState') {
const prevKeys = this.getSlotElements(this.props.tabSlot, this.props).map((el) => el.key);
const nextKeys = this.getSlotElements(next.tabSlot, next).map((el) => el.key);
return !isEqual(prevKeys, nextKeys);
}
// Prevent Slot from rerendering when no props has shallowly changed.
return changes.length !== 0;
}
handleFallback(props = this.props) {
if (this.getTabNames(props).indexOf(props.activeTab) === -1) {
props.setActiveTab(props.fallbackTab);
}
}
getTabNames(props = this.props) {
return this.getTabElements(props).map((el) => el.props.tabId);
}
getSlotElements(slot, props = this.props) {
const {plugins} = this.context;
return plugins.getSlotElements(slot, props.reduxState, props.slotProps, props.queryData);
}
getPluginTabElements(props = this.props) {
return this.getSlotTabElements(props.tabSlot);
}
getPluginTabElementsPrepend(props = this.props) {
return this.getSlotTabElements(props.tabSlotPrepend);
}
getSlotTabElements(slot) {
return this.getSlotElements(slot).map((el) => {
return (
<ExtendableTab tabId={el.type.talkPluginName} key={el.type.talkPluginName}>
{React.cloneElement(el, {active: this.props.activeTab === el.type.talkPluginName})}
</ExtendableTab>
);
});
}
getTabElements(props = this.props) {
const elements = [...this.getPluginTabElementsPrepend(props)];
if (Array.isArray(props.tabs)) {
elements.push(...props.tabs);
} else {
elements.push(props.tabs);
}
elements.push(...this.getPluginTabElements(props));
return elements;
}
getPluginTabPaneElements(props = this.props) {
return this.getSlotElements(props.tabPaneSlot).map((el) => {
return (
<TabPane tabId={el.type.talkPluginName} key={el.type.talkPluginName}>
{el}
</TabPane>
);
});
}
render() {
return (
<ExtendableTabPanel
className={this.props.className}
activeTab={this.props.activeTab}
setActiveTab={this.props.setActiveTab}
tabs={this.getTabElements()}
tabPanes={this.getPluginTabPaneElements().concat(this.props.tabPanes)}
loading={this.props.loading}
sub={this.props.sub}
/>
);
}
}
ExtendableTabPanelContainer.propTypes = {
activeTab: PropTypes.string.isRequired,
setActiveTab: PropTypes.func.isRequired,
tabs: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]),
tabPanes: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]),
fallbackTab: PropTypes.string.isRequired,
tabSlot: PropTypes.string.isRequired,
tabSlotPrepend: PropTypes.string.isRequired,
tabPaneSlot: PropTypes.string.isRequired,
slotProps: PropTypes.object.isRequired,
queryData: PropTypes.object,
className: PropTypes.string,
sub: PropTypes.bool,
loading: PropTypes.bool,
};
const mapStateToProps = (state) => ({
reduxState: state,
});
export default connect(mapStateToProps, null)(ExtendableTabPanelContainer);