import React, { Component } from 'react'; import PropTypes from 'prop-types'; import observeResize from 'simple-element-resize-detector'; import { FaAngleDoubleRight } from 'react-icons/fa'; import ContextMenu from '../ContextMenu'; import createStyledComponent from '../utils/createStyledComponent'; import * as styles from './styles'; const TabsWrapper = createStyledComponent(styles); export type ReactButtonElement = React.ReactElement< JSX.IntrinsicElements['button'], 'button' >; export interface Tab
{ name: string; value?: string; component?: React.ComponentType
; selector?: (tab: this) => P; } interface Props
{ tabs: ReactButtonElement[]; items: Tab
[]; main: boolean | undefined; onClick: (value: string) => void; position: 'left' | 'right' | 'center'; collapsible: boolean | undefined; selected: string | undefined; } interface State { visibleTabs: ReactButtonElement[]; hiddenTabs: ReactButtonElement[]; subMenuOpened: boolean; contextMenu: { top: number; left: number } | undefined; } export default class TabsHeader
extends Component ) {
if (
nextProps.tabs !== this.props.tabs ||
nextProps.selected !== this.props.selected ||
nextProps.collapsible !== this.props.collapsible
) {
this.setState({ hiddenTabs: [], visibleTabs: nextProps.tabs.slice() });
}
}
componentDidMount() {
if (this.props.collapsible) {
this.collapse();
this.enableResizeEvents();
}
}
componentDidUpdate(prevProps: Props ) {
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] as HTMLButtonElement)
.value === 'expandIcon'
) {
this.iconWidth =
tabButtons[tabButtons.length - 1].getBoundingClientRect().width;
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();
}
}
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 (
this.props.position === 'right' &&
hiddenTabs.length > 0 &&
tabsRef!.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
tabsWrapperRef!.getBoundingClientRect().width
) {
while (
i < tabs.length - 1 &&
tabsRef!.getBoundingClientRect().width + this.hiddenTabsWidth[0] <
tabsWrapperRef!.getBoundingClientRect().width
) {
hiddenTab = hiddenTabs.shift();
visibleTabs.splice(Number(hiddenTab!.key), 0, hiddenTab!);
i++;
}
} else {
while (
i > 0 &&
tabButtons[i] &&
tabButtons[i].getBoundingClientRect().right >=
tabsWrapperRight - this.iconWidth
) {
if ((tabButtons[i] as HTMLButtonElement).value !== selected) {
hiddenTabs.unshift(...visibleTabs.splice(i, 1));
this.hiddenTabsWidth.unshift(
tabButtons[i].getBoundingClientRect().width
);
} else {
tabsWrapperRight -= tabButtons[i].getBoundingClientRect().width;
}
i--;
}
}
} else {
while (
i < tabs.length - 1 &&
tabButtons[i] &&
tabButtons[i].getBoundingClientRect().right + this.hiddenTabsWidth[0] <
tabsWrapperRight - this.iconWidth
) {
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: React.RefCallback