nexxtway/react-rainbow

View on GitHub
library/styleguideComponents/ProjectSelector/index.js

Summary

Maintainability
C
1 day
Test Coverage
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable no-script-url */
import React, { Component } from 'react';
import classnames from 'classnames';
import { DOWN_KEY, ESCAPE_KEY, UP_KEY } from '../../../src/libs/constants';
import rainbowLogo from '../../../assets/images/rainbow-logo.svg';
import reactPrismicLogo from '../../../assets/images/react-prismic.svg';
import RenderIf from '../../../src/components/RenderIf';
import MenuDivider from '../../../src/components/MenuDivider';
import RightArrow from './rightArrow';
import './styles.css';
import getLibraryVersion from './get-library-version';

export default class ProjectSelector extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isOpen: false,
            childFocusedIndex: 0,
            componentLibraryVersion: '0.0',
            prismicLibraryVersion: '0.0',
        };
        this.toggleMenu = this.toggleMenu.bind(this);
        this.handleClick = this.handleClick.bind(this);
        this.handleKeyPressed = this.handleKeyPressed.bind(this);
        this.keyHandlerMap = {
            [UP_KEY]: () => this.handleKeyUp(),
            [DOWN_KEY]: () => this.handleKeyDown(),
            [ESCAPE_KEY]: () => this.closeMenu(),
        };
        this.containerRef = React.createRef();
        this.references = Array(1)
            .fill(0)
            .map(() => React.createRef());
    }

    componentDidMount() {
        getLibraryVersion(
            'https://api.github.com/repos/nexxtway/react-rainbow/contents/package.json',
        ).then(version => {
            this.setState({ componentLibraryVersion: version });
        });
        getLibraryVersion(
            'https://api.github.com/repos/reiniergs/react-prismic-cms/contents/package.json',
        ).then(version => {
            this.setState({ prismicLibraryVersion: version });
        });
    }

    getContainerClassNames() {
        const { isOpen } = this.state;
        return classnames('react-rainbow-selector', { 'react-rainbow-selector--open': isOpen });
    }

    handleKeyPressed(event) {
        if (this.keyHandlerMap[event.keyCode]) {
            return this.keyHandlerMap[event.keyCode]();
        }
        return null;
    }

    handleKeyUp() {
        const { childFocusedIndex } = this.state;
        if (this.references.length < 2) {
            return null;
        }
        if (childFocusedIndex === 0) {
            return this.focusChild(this.references.length - 1);
        }
        return this.focusChild(childFocusedIndex - 1);
    }

    handleKeyDown() {
        const { childFocusedIndex } = this.state;
        if (this.references.length < 2) {
            return null;
        }
        if (childFocusedIndex === this.references.length - 1) {
            return this.focusChild(0);
        }
        return this.focusChild(childFocusedIndex + 1);
    }

    focusChild(index) {
        this.setState({ childFocusedIndex: index });
        return this.references[index].current.focus();
    }

    handleClick(event) {
        const isClickInsideMenu = this.containerRef.current.contains(event.target);
        if (isClickInsideMenu) {
            return null;
        }
        return this.closeMenu();
    }

    openMenu() {
        window.addEventListener('click', this.handleClick);
        setTimeout(() => this.focusChild(0), 0);
        return this.setState({
            isOpen: true,
        });
    }

    closeMenu() {
        window.removeEventListener('click', this.handleClick);
        return this.setState({
            isOpen: false,
            childFocusedIndex: -1,
        });
    }

    toggleMenu() {
        const { isOpen } = this.state;
        if (isOpen) {
            return this.closeMenu();
        }
        return this.openMenu();
    }

    render() {
        const { isOpen } = this.state;
        const { componentLibraryVersion, prismicLibraryVersion } = this.state;
        return (
            <ul
                className={this.getContainerClassNames()}
                role="menu"
                onKeyDown={this.handleKeyPressed}
                ref={this.containerRef}
            >
                <li
                    className="react-rainbow-selector_selected-item-section"
                    onClick={this.toggleMenu}
                    role="presentation"
                >
                    <span className="react-rainbow-selector_item">
                        <img
                            src={rainbowLogo}
                            alt="react-rainbow"
                            className="react-rainbow-selector_item-image"
                        />
                        <div className="react-rainbow-selector_item-text">
                            <span className="react-rainbow-selector_item-text_header">
                                react-rainbow-components
                            </span>
                            <span className="react-rainbow-selector_item-text_subheader">
                                version {componentLibraryVersion}
                            </span>
                        </div>
                    </span>
                    <RightArrow isExpanded={isOpen} />
                </li>
                <RenderIf isTrue={isOpen}>
                    <MenuDivider className="react-rainbow-selector_divider" />
                    <li>
                        <a
                            href=" https://react-prismic-cms.web.app/"
                            role="menuitem"
                            ref={this.references[0]}
                            onMouseEnter={() => this.focusChild(0)}
                            className="react-rainbow-selector_item"
                        >
                            <img
                                src={reactPrismicLogo}
                                alt="react-rainbow"
                                className="react-rainbow-selector_item-image"
                            />
                            <div className="react-rainbow-selector_item-text">
                                <span className="react-rainbow-selector_item-text_header">
                                    react-prismic-cms
                                </span>
                                <span className="react-rainbow-selector_item-text_subheader">
                                    version {prismicLibraryVersion}
                                </span>
                            </div>
                        </a>
                    </li>
                </RenderIf>
            </ul>
        );
    }
}

ProjectSelector.propTypes = {};

ProjectSelector.defaultProps = {};