Home Reference Source

src/components/snippets/Panel/PanelShortHand.jsx

import React from 'react';
import {
  compose,
  lifecycle,
  withHandlers,
  withState,
  defaultProps,
} from 'recompose';
import PropTypes from 'prop-types';
import { isEmpty, isEqual, set } from 'lodash';
import cn from 'classnames';

import Panel from './Panel';
import panelStyles from './panelStyles';

/**
 * Shorthand для создания панели
 * @reactProps {array} tabs - массив с табами
 * @reactProps {array} toolbar - массив для тулбара
 * @reactProps {string} className - имя класса для родительского элемента
 * @reactProps {object} style - стили для родительского элемента
 * @reactProps {string} color - стиль для панели
 * @reactProps {string} icon - класс для иконки
 * @reactProps {string} headerTitle - заголовок для шапки
 * @reactProps {string} footerTitle - заголовок для футера
 * @reactProps {boolean} collapsible - флаг возможности скрывать содержимое панели
 * @reactProps {boolean} open - флаг открытости панели
 * @reactProps {boolean} hasTabs - флаг наличия табов
 * @reactProps {boolean} fullScreen - флаг возможности открывать на полный экран
 * @reactProps {node} children - элемент вставляемый в PanelContainer
 * @reactProps {boolean} - флаг показа заголовка
 * @example <caption>Структура tabs</caption>
 * {
 *  id - id таба
 *  header - содержимое нава
 *  content - содержимое таба
 * }
 */

function PanelContainer({
  tabs,
  toolbar,
  className,
  style,
  color,
  icon,
  headerTitle,
  footerTitle,
  collapsible,
  hasTabs,
  fullScreen,
  header,
  fullScreenState,
  openState,
  activeTabState,
  children,
  handleFullScreen,
  changeActiveTab,
  toggleCollapse,
  handleKeyPress,
  innerRef,
}) {
  const fullScreenIcon = fullScreenState ? 'fa-compress' : 'fa-expand';

  return (
    <Panel
      color={color}
      style={style}
      className={cn(className, {
        'n2o-panel-region--tabs': hasTabs,
      })}
      open={openState}
      isFullScreen={fullScreenState}
      onKeyPress={handleKeyPress}
      innerRef={innerRef}
    >
      {header && (
        <Panel.Heading>
          <Panel.Title collapsible={collapsible} icon={icon}>
            {headerTitle}
          </Panel.Title>
          <Panel.Menu
            fullScreen={fullScreen}
            onFullScreenClick={handleFullScreen}
            fullScreenIcon={fullScreenIcon}
            isOpen={openState}
            onToggle={toggleCollapse}
            collapsible={collapsible}
          >
            {hasTabs &&
              tabs.map((tab, i) => {
                let activeTab = activeTabState;

                if (!activeTab && i === 0) {
                  changeActiveTab(tab.id);
                }

                return (
                  <Panel.NavItem
                    id={tab.id}
                    active={activeTab === tab.id}
                    disabled={tab.disabled}
                    className={cn('nav-item--tab', tab.className)}
                    style={tab.style}
                    onClick={() => changeActiveTab(tab.id)}
                  >
                    {tab.header}
                  </Panel.NavItem>
                );
              })}
            {toolbar &&
              toolbar.map(item => (
                <Panel.NavItem
                  id={item.id}
                  disabled={item.disabled}
                  className={cn('nav-item--toolbar', item.className)}
                  style={item.style}
                  onClick={item.onClick}
                  isToolBar={true}
                >
                  {item.header}
                </Panel.NavItem>
              ))}
          </Panel.Menu>
        </Panel.Heading>
      )}
      <Panel.Collapse
        className={cn({
          'd-flex flex-column n2o-panel-region--grow': openState,
        })}
        isOpen={openState}
      >
        <Panel.Body hasTabs={hasTabs} activeKey={activeTabState}>
          {hasTabs
            ? tabs.map(tab => {
                return (
                  <Panel.TabBody eventKey={tab.id}>{tab.content}</Panel.TabBody>
                );
              })
            : children}
        </Panel.Body>
        {footerTitle && <Panel.Footer>{footerTitle}</Panel.Footer>}
      </Panel.Collapse>
    </Panel>
  );
}

PanelContainer.propTypes = {
  tabs: PropTypes.array,
  toolbar: PropTypes.array,
  className: PropTypes.string,
  style: PropTypes.object,
  color: PropTypes.oneOf(Object.values(panelStyles)),
  icon: PropTypes.string,
  headerTitle: PropTypes.string,
  footerTitle: PropTypes.string,
  open: PropTypes.bool,
  collapsible: PropTypes.bool,
  hasTabs: PropTypes.bool,
  fullScreen: PropTypes.bool,
  children: PropTypes.node,
  header: PropTypes.bool,
  isFullScreen: PropTypes.bool,
  onKeyPress: PropTypes.func,
  innerRef: PropTypes.func,
};

export default compose(
  defaultProps({
    open: true,
    collapsible: false,
    hasTabs: false,
    fullScreen: false,
    tabs: [],
    color: panelStyles.DEFAULT,
    header: true,
    onKeyPress: () => {},
  }),
  withState(
    'fullScreenState',
    'setFullScreenState',
    ({ isFullScreen }) => isFullScreen
  ),
  withState('activeTabState', 'setActiveTabState', ({ tabs }) =>
    tabs.length > 0 ? tabs[0].id : null
  ),
  withState('openState', 'setOpenState', ({ open }) => open),
  withHandlers({
    handleFullScreen: ({ fullScreenState, setFullScreenState }) => () =>
      setFullScreenState(!fullScreenState),
    changeActiveTab: ({ setActiveTabState }) => id => setActiveTabState(id),
    toggleCollapse: ({ openState, setOpenState }) => () =>
      setOpenState(!openState),
    handleKeyPress: ({ setFullScreenState, onKeyPress }) => event => {
      if (event.key === 'Escape') {
        setFullScreenState(false);
        onKeyPress(false);
      }
    },
  }),
  lifecycle({
    componentDidUpdate(prevProps) {
      if (!isEqual(prevProps, this.props)) {
        const { open, isFullScreen } = this.props;
        const state = {};

        if (prevProps.open !== open) {
          set(state, 'openState', open);
        }

        if (prevProps.isFullScreen !== isFullScreen) {
          set(state, 'fullScreenState', isFullScreen);
        }

        this.setState(state);
      }
    },
  })
)(PanelContainer);