redux-devtools/packages/devui/src/Tabs/TabsHeader.js

216 lines
6.0 KiB
JavaScript
Raw Normal View History

2019-01-03 16:00:55 +03:00
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import observeResize from 'simple-element-resize-detector';
import { FaAngleDoubleRight } from 'react-icons/fa';
2019-01-03 16:00:55 +03:00
import ContextMenu from '../ContextMenu';
import createStyledComponent from '../utils/createStyledComponent';
import * as styles from './styles';
const TabsWrapper = createStyledComponent(styles);
export default class TabsHeader extends Component {
constructor(props) {
super(props);
this.state = {
visibleTabs: props.tabs.slice(),
hiddenTabs: [],
subMenuOpened: false,
contextMenu: undefined,
2019-01-03 16:00:55 +03:00
};
this.iconWidth = 0;
this.hiddenTabsWidth = [];
}
UNSAFE_componentWillReceiveProps(nextProps) {
2019-01-10 21:51:14 +03:00
if (
nextProps.tabs !== this.props.tabs ||
2019-01-03 16:00:55 +03:00
nextProps.selected !== this.props.selected ||
2019-01-10 21:51:14 +03:00
nextProps.collapsible !== this.props.collapsible
) {
2019-01-03 16:00:55 +03:00
this.setState({ hiddenTabs: [], visibleTabs: nextProps.tabs.slice() });
}
}
componentDidMount() {
if (this.props.collapsible) {
this.collapse();
this.enableResizeEvents();
}
}
componentDidUpdate(prevProps) {
const { collapsible } = this.props;
if (!collapsible) {
if (prevProps.collapsible !== collapsible) this.disableResizeEvents();
return;
}
let shouldCollapse = false;
if (this.iconWidth === 0) {
const tabButtons = this.tabsRef.children;
if (this.tabsRef.children[tabButtons.length - 1].value === 'expandIcon') {
2019-01-10 21:51:14 +03:00
this.iconWidth = tabButtons[
tabButtons.length - 1
].getBoundingClientRect().width;
2019-01-03 16:00:55 +03:00
shouldCollapse = true;
}
} else if (this.state.hiddenTabs.length === 0) {
this.iconWidth = 0;
}
if (prevProps.collapsible !== collapsible) {
this.enableResizeEvents();
shouldCollapse = true;
}
if (shouldCollapse || this.props.selected !== prevProps.selected) {
this.collapse();
}
}
componentWillUnmount() {
if (this.props.collapsible) {
this.disableResizeEvents();
}
2019-01-03 16:00:55 +03:00
}
enableResizeEvents() {
this.resizeDetector = observeResize(this.tabsWrapperRef, this.collapse);
window.addEventListener('mousedown', this.hideSubmenu);
}
disableResizeEvents() {
this.resizeDetector.remove();
window.removeEventListener('mousedown', this.hideSubmenu);
}
collapse = () => {
if (this.state.subMenuOpened) this.hideSubmenu();
const { selected, tabs } = this.props;
const tabsWrapperRef = this.tabsWrapperRef;
const tabsRef = this.tabsRef;
const tabButtons = this.tabsRef.children;
const visibleTabs = this.state.visibleTabs;
const hiddenTabs = this.state.hiddenTabs;
let tabsWrapperRight = tabsWrapperRef.getBoundingClientRect().right;
if (!tabsWrapperRight) return; // tabs are hidden
const tabsRefRight = tabsRef.getBoundingClientRect().right;
let i = visibleTabs.length - 1;
let hiddenTab;
if (tabsRefRight >= tabsWrapperRight - this.iconWidth) {
if (
2019-01-10 21:51:14 +03:00
this.props.position === 'right' &&
hiddenTabs.length > 0 &&
2019-01-03 16:00:55 +03:00
tabsRef.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
2019-01-10 21:51:14 +03:00
tabsWrapperRef.getBoundingClientRect().width
2019-01-03 16:00:55 +03:00
) {
while (
i < tabs.length - 1 &&
tabsRef.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
2019-01-10 21:51:14 +03:00
tabsWrapperRef.getBoundingClientRect().width
2019-01-03 16:00:55 +03:00
) {
hiddenTab = hiddenTabs.shift();
visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);
i++;
}
} else {
while (
2019-01-10 21:51:14 +03:00
i > 0 &&
tabButtons[i] &&
tabButtons[i].getBoundingClientRect().right >=
tabsWrapperRight - this.iconWidth
2019-01-03 16:00:55 +03:00
) {
if (tabButtons[i].value !== selected) {
hiddenTabs.unshift(...visibleTabs.splice(i, 1));
2019-01-10 21:51:14 +03:00
this.hiddenTabsWidth.unshift(
tabButtons[i].getBoundingClientRect().width
);
2019-01-03 16:00:55 +03:00
} else {
tabsWrapperRight -= tabButtons[i].getBoundingClientRect().width;
}
i--;
}
}
} else {
while (
2019-01-10 21:51:14 +03:00
i < tabs.length - 1 &&
tabButtons[i] &&
tabButtons[i].getBoundingClientRect().right + this.hiddenTabsWidth[0] <
tabsWrapperRight - this.iconWidth
2019-01-03 16:00:55 +03:00
) {
hiddenTab = hiddenTabs.shift();
visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);
this.hiddenTabsWidth.shift();
i++;
}
}
this.setState({ visibleTabs, hiddenTabs });
};
hideSubmenu = () => {
this.setState({ subMenuOpened: false, contextMenu: undefined });
};
getTabsWrapperRef = (node) => {
2019-01-03 16:00:55 +03:00
this.tabsWrapperRef = node;
};
getTabsRef = (node) => {
2019-01-03 16:00:55 +03:00
this.tabsRef = node;
};
expandMenu = (e) => {
2019-01-03 16:00:55 +03:00
const rect = e.currentTarget.children[0].getBoundingClientRect();
this.setState({
contextMenu: {
top: rect.top + 10,
left: rect.left,
2019-01-03 16:00:55 +03:00
},
subMenuOpened: true,
2019-01-03 16:00:55 +03:00
});
};
render() {
const { visibleTabs, hiddenTabs, contextMenu } = this.state;
return (
<TabsWrapper
innerRef={this.getTabsWrapperRef}
main={this.props.main}
position={this.props.position}
>
<div ref={this.getTabsRef}>
{visibleTabs}
2019-01-10 21:51:14 +03:00
{this.props.collapsible &&
visibleTabs.length < this.props.items.length && (
<button onClick={this.expandMenu} value="expandIcon">
<FaAngleDoubleRight />
2019-01-10 21:51:14 +03:00
</button>
)}
2019-01-03 16:00:55 +03:00
</div>
2019-01-10 21:51:14 +03:00
{this.props.collapsible && contextMenu && (
2019-01-03 16:00:55 +03:00
<ContextMenu
items={hiddenTabs}
onClick={this.props.onClick}
x={contextMenu.left}
y={contextMenu.top}
visible={this.state.subMenuOpened}
/>
2019-01-10 21:51:14 +03:00
)}
2019-01-03 16:00:55 +03:00
</TabsWrapper>
);
}
}
TabsHeader.propTypes = {
tabs: PropTypes.array.isRequired,
items: PropTypes.array.isRequired,
main: PropTypes.bool,
onClick: PropTypes.func,
position: PropTypes.string,
collapsible: PropTypes.bool,
selected: PropTypes.string,
2019-01-03 16:00:55 +03:00
};