import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2020. Plesk International GmbH. All rights reserved.
import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
import Measure from 'react-measure';
import classNames from 'classnames';
import { CSSTransition } from 'react-transition-group';
import { CLS_PREFIX } from '../../constants';
const propTypes = {
  /**
   * Type of the `Layout`
   * @since 1.4.0
   */
  type: PropTypes.oneOf(['fluid', 'simplified']),

  /**
   * Header content.
   * @since 1.4.0
   */
  header: PropTypes.node,

  /**
   * Define header position - always on top (fixed) or static.
   * @since 1.4.0
   */
  headerFixed: PropTypes.bool,

  /**
   * Additional content at the top of the header.
   * @since 3.2.0
   */
  headerAddon: PropTypes.node,

  /**
   * Sidebar content.
   * @since 1.4.0
   */
  sidebar: PropTypes.node,

  /**
   * Sidebar type.
   * @since 3.2.0
   */
  sidebarType: PropTypes.oneOf(['collapsed', 'folded']),

  /**
   * Define if sidebar can collapse.
   * @since 1.4.0
   */
  sidebarCollapsible: PropTypes.bool,

  /**
   * Sidebar collapsed state.
   * A boolean value is used for desktop mode only, but you can set an array with collapsed states for all modes, e.g. `['responsive', 'desktop']`.
   *
   * @since 1.4.0
   */
  sidebarCollapsed: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),

  /**
   * Additional content between header and main content.
   * @since 1.4.0
   */
  contentAddon: PropTypes.node,

  /**
   * Content header.
   * @since 3.0.0
   */
  contentHeader: PropTypes.node,

  /**
   * Footer content.
   * @since 1.4.0
   */
  footer: PropTypes.node,

  /**
   * Main content of the `Layout`.
   * @since 1.4.0
   */
  children: PropTypes.node,

  /**
   * Width of the content
   * @since 3.0.0
   */
  width: PropTypes.oneOf(['sm', 'md', 'lg']),

  /**
   * Sidebar onToggle handler.
   * The handler is called with two args:
   *
   * * Whether collapsed or not.
   * * In which mode: responsive or desktop.
   *
   * @since 1.4.0
   */
  onSidebarToggle: PropTypes.func,

  /**
   * @ignore
   */
  className: PropTypes.string,

  /**
   * @ignore
   */
  baseClassName: PropTypes.string
};
const defaultProps = {
  type: 'fluid',
  header: undefined,
  headerFixed: true,
  headerAddon: undefined,
  sidebar: undefined,
  sidebarType: 'collapsed',
  sidebarCollapsible: true,
  sidebarCollapsed: false,
  contentAddon: undefined,
  contentHeader: undefined,
  footer: undefined,
  width: undefined,
  onSidebarToggle: undefined,
  children: undefined,
  className: undefined,
  baseClassName: `${CLS_PREFIX}layout`
};

const subscribeMatchMedia = (query, handler) => {
  const mq = window.matchMedia(query);
  handler(mq);
  mq.addListener(handler);
  return () => {
    mq.removeListener(handler);
  };
};

const subscribeClickOutside = (refs, handler) => {
  const listener = event => {
    if (refs.some(({
      current
    }) => !current || current.contains(event.target))) {
      return;
    }

    handler(event);
  };

  document.addEventListener('mousedown', listener);
  document.addEventListener('touchstart', listener);
  return () => {
    document.removeEventListener('mousedown', listener);
    document.removeEventListener('touchstart', listener);
  };
};
/**
 * @since 1.4.0
 */


export default class Layout extends Component {
  constructor(props) {
    super(props);

    _defineProperty(this, "state", {
      isSidebarClosedResponsive: true,
      headerHeight: null,
      isResponsive: window.matchMedia('(max-width: 1022px)').matches
    });

    _defineProperty(this, "handleMatchMedia", ({
      matches
    }) => {
      this.setState({
        isResponsive: matches
      });
    });

    _defineProperty(this, "handleClickOutside", () => {
      const {
        isResponsive
      } = this.state;

      if (isResponsive) {
        this.setState({
          isSidebarClosedResponsive: true
        });
      }
    });

    _defineProperty(this, "handleToggle", () => {
      this.setState(prevState => {
        const key = prevState.isResponsive ? 'isSidebarClosedResponsive' : 'isSidebarClosedDesktop';
        return {
          [key]: !prevState[key]
        };
      }, () => {
        if (this.props.onSidebarToggle) {
          this.props.onSidebarToggle(this.getSidebarClosed(), this.state.isResponsive ? 'responsive' : 'desktop');
        }
      });
    });

    _defineProperty(this, "handleResize", ({
      bounds
    }) => {
      this.setState({
        headerHeight: bounds.height
      });
    });

    _defineProperty(this, "getSidebarClosed", () => {
      const {
        isResponsive,
        isSidebarClosedResponsive,
        isSidebarClosedDesktop
      } = this.state;
      return isResponsive ? isSidebarClosedResponsive : isSidebarClosedDesktop;
    });

    this.headerRef = /*#__PURE__*/createRef();
    this.sidebarRef = /*#__PURE__*/createRef();
    this.responsiveSidebarTogglerRef = /*#__PURE__*/createRef();
  }

  static getDerivedStateFromProps(props, state) {
    const {
      sidebarCollapsed
    } = props;
    const {
      prevSidebarCollapsed
    } = state;
    const nextState = {};

    if (sidebarCollapsed !== prevSidebarCollapsed) {
      if (Array.isArray(sidebarCollapsed)) {
        nextState.isSidebarClosedDesktop = sidebarCollapsed.includes('desktop');
        nextState.isSidebarClosedResponsive = sidebarCollapsed.includes('responsive');
      } else {
        nextState.isSidebarClosedDesktop = Boolean(sidebarCollapsed);
      }
    }

    nextState.prevSidebarCollapsed = sidebarCollapsed;
    return nextState;
  }

  componentDidMount() {
    this.unsubscribeMatchMedia = subscribeMatchMedia('(max-width: 1022px)', this.handleMatchMedia);
    this.unsubscribeClickOutside = subscribeClickOutside([this.sidebarRef, this.responsiveSidebarTogglerRef], this.handleClickOutside);
  }

  componentWillUnmount() {
    this.unsubscribeMatchMedia();
    this.unsubscribeClickOutside();
  }

  renderHeader({
    header
  }) {
    const {
      baseClassName,
      headerAddon,
      sidebar
    } = this.props;
    const {
      headerHeight
    } = this.state;

    if (!header) {
      return null;
    }

    const isSidebarClosed = this.getSidebarClosed();
    return /*#__PURE__*/React.createElement(CSSTransition, {
      in: !isSidebarClosed,
      timeout: 300,
      classNames: {
        enter: `${baseClassName}__header--enter`,
        enterActive: `${baseClassName}__header--active-enter`,
        enterDone: `${baseClassName}__header--on`,
        exit: `${baseClassName}__header--exit`,
        exitActive: `${baseClassName}__header--active-exit`,
        exitDone: `${baseClassName}__header--off`
      },
      nodeRef: this.headerRef
    }, /*#__PURE__*/React.createElement("header", {
      className: `${baseClassName}__header`,
      ref: this.headerRef,
      style: {
        height: `${headerHeight}px`
      }
    }, /*#__PURE__*/React.createElement(Measure, {
      onResize: this.handleResize,
      bounds: true
    }, ({
      measureRef
    }) => /*#__PURE__*/React.createElement("div", {
      ref: measureRef,
      className: `${baseClassName}__header-inner`
    }, headerAddon ? /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__header-addon`
    }, headerAddon) : null, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__header-content`
    }, sidebar && /*#__PURE__*/React.createElement("button", {
      className: classNames(`${baseClassName}__responsive-sidebar-toggler`, {
        [`${baseClassName}__responsive-sidebar-toggler--open`]: !isSidebarClosed
      }),
      type: "button",
      onClick: this.handleToggle,
      ref: this.responsiveSidebarTogglerRef
    }, /*#__PURE__*/React.createElement("span", {
      className: `${baseClassName}__responsive-sidebar-toggler-inner`
    }, /*#__PURE__*/React.createElement("span", {
      className: `${baseClassName}__responsive-sidebar-toggler-icon`
    }))), /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__header-content-inner`
    }, header))))));
  }

  renderContentAddon({
    contentAddon
  }) {
    const {
      baseClassName
    } = this.props;

    if (!contentAddon) {
      return null;
    }

    return /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__content-addon`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__content-addon-inner`
    }, contentAddon));
  }

  renderContentHeader({
    contentHeader
  }) {
    const {
      baseClassName
    } = this.props;

    if (!contentHeader) {
      return null;
    }

    return /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__content-header`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__content-header-inner`
    }, contentHeader));
  }

  renderSidebar({
    sidebar
  }) {
    const {
      baseClassName,
      sidebarCollapsible,
      type
    } = this.props;

    if (!sidebar || type === 'simplified') {
      return null;
    }

    const isSidebarClosed = this.getSidebarClosed();
    return /*#__PURE__*/React.createElement(CSSTransition, {
      in: !isSidebarClosed,
      timeout: 300,
      classNames: {
        enter: `${baseClassName}__sidebar--enter`,
        enterActive: `${baseClassName}__sidebar--active-enter`,
        enterDone: `${baseClassName}__sidebar--on`,
        exit: `${baseClassName}__sidebar--exit`,
        exitActive: `${baseClassName}__sidebar--active-exit`,
        exitDone: `${baseClassName}__sidebar--off`
      }
    }, /*#__PURE__*/React.createElement("aside", {
      className: classNames(`${baseClassName}__sidebar`, {
        [`${baseClassName}__sidebar--on`]: !isSidebarClosed,
        [`${baseClassName}__sidebar--off`]: isSidebarClosed
      }),
      ref: this.sidebarRef
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__sidebar-inner`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__sidebar-content`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__sidebar-content-inner`
    }, sidebar)), sidebarCollapsible && /*#__PURE__*/React.createElement("button", {
      className: `${baseClassName}__sidebar-toggler`,
      onClick: this.handleToggle,
      type: "button"
    }, /*#__PURE__*/React.createElement("span", {
      className: `${baseClassName}__sidebar-toggler-inner`
    })))));
  }

  renderMainContent({
    children
  }) {
    const {
      baseClassName
    } = this.props;
    return /*#__PURE__*/React.createElement("main", {
      className: `${baseClassName}__main`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__main-inner`
    }, children));
  }

  renderFooter({
    footer
  }) {
    const {
      baseClassName
    } = this.props;

    if (!footer) {
      return null;
    }

    return /*#__PURE__*/React.createElement("footer", {
      className: `${baseClassName}__footer`
    }, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__footer-inner`
    }, footer));
  }

  render() {
    const {
      baseClassName,
      className,
      children,
      type,
      header,
      headerFixed,
      headerAddon,
      sidebar,
      sidebarType,
      sidebarCollapsible,
      sidebarCollapsed,
      onSidebarToggle,
      contentAddon,
      contentHeader,
      footer,
      width: widthProp,
      ...props
    } = this.props;
    let width = widthProp;
    let headerPositionFixed = headerFixed;

    if (type === 'simplified') {
      headerPositionFixed = false;

      if (!width) {
        width = 'sm';
      }
    }

    const isSidebarClosed = this.getSidebarClosed();
    return /*#__PURE__*/React.createElement("div", _extends({
      className: classNames(baseClassName, {
        [`${baseClassName}--${type}`]: type,
        [`${baseClassName}--${width}`]: width,
        [`${baseClassName}--touch`]: 'ontouchstart' in document.documentElement,
        [`${baseClassName}--header`]: header,
        [`${baseClassName}--header-fixed`]: header && headerPositionFixed,
        [`${baseClassName}--sidebar`]: sidebar,
        [`${baseClassName}--sidebar-type-${sidebarType}`]: sidebarType && sidebar,
        [`${baseClassName}--sidebar-collapsed`]: sidebarType === 'collapsed' && isSidebarClosed,
        [`${baseClassName}--sidebar-folded`]: sidebarType === 'folded' && isSidebarClosed
      }, className)
    }, props), /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__inner`
    }, this.renderHeader({
      header
    }), /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__container`
    }, this.renderSidebar({
      sidebar,
      headerFixed: headerPositionFixed
    }), /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__content`
    }, this.renderContentAddon({
      contentAddon
    }), this.renderContentHeader({
      contentHeader
    }), this.renderMainContent({
      children
    }), this.renderFooter({
      footer
    })))));
  }

}
Layout.propTypes = propTypes;
Layout.defaultProps = defaultProps;