nexxtway/react-rainbow

View on GitHub
src/components/Tab/index.js

Summary

Maintainability
C
7 hrs
Test Coverage
/* eslint-disable no-script-url, react/prop-types */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Consumer } from '../Tabset/context';
import StyledContainer from './styled/container';
import TruncatedText from '../Structural/truncatedText';
import StyledButton from './styled/button';

class TabItem extends Component {
    constructor(props) {
        super(props);
        this.tabRef = React.createRef();
        this.handleSelect = this.handleSelect.bind(this);
    }

    componentDidMount() {
        const { privateRegisterTab, name, disabled } = this.props;
        if (!disabled) {
            privateRegisterTab({ name, ref: this.tabRef.current });
        }
    }

    componentDidUpdate({ name: prevName }) {
        const { name, privateUpdateTab } = this.props;
        if (name !== prevName) {
            privateUpdateTab({ name, ref: this.tabRef.current }, prevName);
        }
    }

    componentWillUnmount() {
        const { privateUnRegisterTab, name } = this.props;
        privateUnRegisterTab(name);
    }

    getTabIndex() {
        if (this.isSelected()) {
            return 0;
        }
        return -1;
    }

    handleSelect(event) {
        const { disabled, onSelect, name } = this.props;
        if (!disabled) {
            onSelect(event, name);
        }
    }

    isSelected() {
        const { activeTabName, name } = this.props;
        return activeTabName === name;
    }

    render() {
        const {
            label,
            style,
            className,
            title,
            id,
            ariaControls,
            fullWidth,
            variant,
            disabled,
        } = this.props;
        const isActive = this.isSelected();

        return (
            <StyledContainer
                className={className}
                fullWidth={fullWidth}
                variant={variant}
                isActive={isActive}
                style={style}
                title={title}
                role="presentation"
            >
                <StyledButton
                    role="tab"
                    type="button"
                    aria-selected={isActive}
                    onClick={this.handleSelect}
                    tabIndex={this.getTabIndex()}
                    id={id}
                    aria-controls={ariaControls}
                    ref={this.tabRef}
                    isActive={isActive}
                    disabled={disabled}
                    fullWidth={fullWidth}
                    variant={variant}
                    data-active={isActive}
                >
                    <TruncatedText>{label}</TruncatedText>
                </StyledButton>
            </StyledContainer>
        );
    }
}

/** @category Layout */
export default function Tab(props) {
    // eslint-disable-next-line react/jsx-props-no-spreading
    return <Consumer>{context => <TabItem {...props} {...context} />}</Consumer>;
}

Tab.propTypes = {
    /** The text displayed for the tab item. */
    label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
    /** The name is used during tabset's onSelect
     * event to determine which tab was clicked. */
    name: PropTypes.string,
    /** Displays tooltip text when the mouse moves over the element. */
    title: PropTypes.string,
    /** Specifies whether this tab should be displayed in a disabled state.
     * Disabled tabs can't be clicked. This value defaults to false. */
    disabled: PropTypes.bool,
    /** This ID is to be associated with the aria-labelledby attribute of the container
     * that show the content of this tab. */
    id: PropTypes.string,
    /** This prop is associated with the id attribute of the container
     * that show the content of this tab. */
    ariaControls: PropTypes.string,
    /** A CSS class for the outer element, in addition to the component's base classes. */
    className: PropTypes.string,
    /** An object with custom style applied for the outer element. */
    style: PropTypes.object,
};

Tab.defaultProps = {
    label: null,
    name: undefined,
    title: undefined,
    disabled: false,
    id: undefined,
    ariaControls: undefined,
    className: undefined,
    style: undefined,
};