'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var clsx = require('clsx');
var clamp = require('lodash.clamp');
var React = require('react');
require('../common/theme.js');
var direction = require('../common/direction.js');
require('@transferwise/neptune-tokens');
require('../common/propsValues/control.js');
require('../common/propsValues/size.js');
require('../common/propsValues/typography.js');
var width = require('../common/propsValues/width.js');
require('../common/propsValues/type.js');
require('../common/propsValues/dateMode.js');
require('../common/propsValues/monthFormat.js');
require('../common/propsValues/position.js');
require('../common/propsValues/layouts.js');
require('../common/propsValues/status.js');
require('../common/propsValues/sentiment.js');
require('../common/propsValues/profileType.js');
require('../common/propsValues/variant.js');
require('../common/propsValues/scroll.js');
require('../common/propsValues/markdownNodeType.js');
require('../common/fileType.js');
require('@transferwise/formatting');
require('@transferwise/icons');
require('react-intl');
require('../common/closeButton/CloseButton.messages.js');
var jsxRuntime = require('react/jsx-runtime');
var DirectionProvider = require('../provider/direction/DirectionProvider.js');
var Tab = require('./Tab.js');
var TabList = require('./TabList.js');
var TabPanel = require('./TabPanel.js');
var utils = require('./utils.js');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var clamp__default = /*#__PURE__*/_interopDefault(clamp);

const MIN_INDEX = 0;
class Tabs extends React.Component {
  static defaultProps = {
    changeTabOnSwipe: true,
    headerWidth: width.Width.BLOCK
  };
  containerReference = /*#__PURE__*/React.createRef();
  constructor(props) {
    super(props);
    this.state = {
      start: null,
      translateLineX: null,
      isSwiping: false,
      isScrolling: false,
      fullWidthTabs: props.headerWidth === width.Width.BLOCK
    };
  }
  container = null;
  containerWidth = 0;
  tabRefs = [];
  get MAX_INDEX() {
    return this.props.tabs.length - 1;
  }
  componentDidMount() {
    const {
      selected
    } = this.props;
    this.setTabWidth();
    this.switchTab(clamp__default.default(selected, MIN_INDEX, this.MAX_INDEX));
    this.animateLine(clamp__default.default(selected, MIN_INDEX, this.MAX_INDEX));
    document.body.addEventListener('touchmove', this.disableScroll, {
      passive: false
    });
    document.body.addEventListener('touchforcechange', this.disableScroll, {
      passive: false
    });
    window.addEventListener('resize', this.handleResize);
  }
  componentDidUpdate(previousProps) {
    const currentSelected = this.props.selected;
    const previousSelected = previousProps.selected;
    const currentSelectedTab = this.props.tabs[currentSelected];
    const currentSelectedTabIsDisabled = currentSelectedTab?.disabled;
    const previousSelectedTab = previousProps.tabs[previousSelected];
    const previousSelectedTabIsDisabled = previousSelectedTab?.disabled;
    const currentTabsLength = this.props.tabs.length;
    const previousTabsLength = previousProps.tabs.length;
    const currentDisabledTabsLength = this.props.tabs.filter(tab => !tab.disabled).length;
    const previousDisabledTabsLength = previousProps.tabs.filter(tab => !tab.disabled).length;
    const currentHeaderWidth = this.props.headerWidth;
    const previousFullHeaderWidth = previousProps.headerWidth;
    if (currentHeaderWidth !== previousFullHeaderWidth || currentTabsLength !== previousTabsLength) {
      this.setTabWidth();
    }
    if (currentSelected !== previousSelected || currentDisabledTabsLength !== previousDisabledTabsLength || currentSelectedTabIsDisabled !== previousSelectedTabIsDisabled) {
      this.animateLine(clamp__default.default(currentSelected, MIN_INDEX, this.MAX_INDEX));
    }
  }
  componentWillUnmount() {
    document.body.removeEventListener('touchmove', this.disableScroll);
    document.body.removeEventListener('touchforcechange', this.disableScroll);
    window.removeEventListener('resize', this.handleResize);
  }
  handleResize = () => {
    this.setContainerWidth(this.container);
  };
  setContainerRefAndWidth = node => {
    this.container = node;
    this.setContainerWidth(node);
  };
  setContainerWidth = node => {
    if (!node) {
      return;
    }
    const {
      width
    } = node.getBoundingClientRect();
    this.containerWidth = width;
  };
  isTabDisabled = index => {
    const {
      tabs
    } = this.props;
    return tabs[index]?.disabled ?? false;
  };
  getAllTabsWidth = () => {
    return this.tabRefs.map(reference => {
      return reference ? reference.getBoundingClientRect().width : 0;
    }).reduce((a, b) => a + b, 0);
  };
  getDistanceToSelectedTab = selectedTabIndex => {
    return this.tabRefs.filter((_, idx) => idx < selectedTabIndex).map(reference => reference ? reference.getBoundingClientRect().width : 0).reduce((a, b) => a + b, 0);
  };
  setTabWidth = () => {
    const {
      fullWidthTabs
    } = this.state;
    const {
      headerWidth,
      selected
    } = this.props;
    const allTabsWidth = this.getAllTabsWidth();
    if (!fullWidthTabs && (headerWidth === width.Width.BLOCK || this.containerWidth < allTabsWidth)) {
      this.setState({
        fullWidthTabs: true,
        translateLineX: `${selected * 100}%`
      });
    }
    if (fullWidthTabs && headerWidth === width.Width.AUTO && this.containerWidth >= allTabsWidth) {
      this.setState({
        fullWidthTabs: false,
        translateLineX: `${this.getDistanceToSelectedTab(selected)}px`
      });
    }
  };
  getTabLineWidth = () => {
    const {
      fullWidthTabs
    } = this.state;
    const {
      selected,
      tabs
    } = this.props;
    if (fullWidthTabs) {
      return `${1 / tabs.length * 100}%`;
    }
    const reference = this.tabRefs[selected] || this.tabRefs[this.tabRefs.length - 1];
    const width = reference ? reference.getBoundingClientRect().width : 0;
    return `${width}px`;
  };
  /*
   * Gets the next tab that should be selected based on the swipe direction
   * and the current selected tab (is called recursively to account for disabled tabs).
   */
  getTabToSelect = (selected, start, end) => {
    let nextSelected = selected;
    if (utils.swipedLeftToRight(start, end)) {
      nextSelected -= 1;
      if (nextSelected > MIN_INDEX && this.isTabDisabled(nextSelected)) {
        return this.getTabToSelect(nextSelected, start, end);
      }
    } else if (utils.swipedRightToLeft(start, end)) {
      nextSelected += 1;
      if (nextSelected < this.MAX_INDEX && this.isTabDisabled(nextSelected)) {
        return this.getTabToSelect(nextSelected, start, end);
      }
    }
    nextSelected = clamp__default.default(nextSelected, Math.max(selected - 1, MIN_INDEX), Math.min(selected + 1, this.MAX_INDEX));
    if (this.isTabDisabled(nextSelected)) {
      return selected;
    }
    return nextSelected;
  };
  swipedOverHalfOfContainer = difference => difference / this.containerWidth >= 0.5;
  switchTab = index => {
    const {
      onTabSelect
    } = this.props;
    onTabSelect(index);
  };
  animateLine = index => {
    this.setState(previousState => ({
      translateLineX: previousState.fullWidthTabs ? `${index * 100}%` : `${this.getDistanceToSelectedTab(index)}px`
    }));
  };
  disableScroll = event => {
    const {
      isSwiping
    } = this.state;
    if (isSwiping) {
      event.preventDefault();
    }
  };
  handleTabClick = index => () => {
    this.switchTab(index);
  };
  onKeyDown = index => event => {
    if (event?.key === 'Enter') {
      this.switchTab(index);
    }
  };
  handleTouchStart = event => {
    const start = {
      x: event.nativeEvent.touches[0].clientX,
      y: event.nativeEvent.touches[0].clientY,
      time: Date.now()
    };
    this.setState({
      start
    });
  };
  handleTouchMove = event => {
    const {
      start
    } = this.state;
    if (start == null) {
      return;
    }
    const {
      selected: currentSelectedFromProps
    } = this.props;
    const end = {
      x: event.nativeEvent.changedTouches[0].clientX,
      y: event.nativeEvent.changedTouches[0].clientY,
      time: Date.now()
    };
    const difference = utils.getSwipeDifference(start, end);
    const yAxisDifference = utils.getSwipeDifference(start, end, 'y');
    let {
      isScrolling,
      isSwiping
    } = this.state;
    if (!isScrolling && !isSwiping) {
      if (difference > yAxisDifference) {
        isSwiping = true;
      } else {
        isScrolling = true;
      }
    }
    this.setState({
      isScrolling,
      isSwiping
    });
    if (isSwiping) {
      const nextSelected = this.getTabToSelect(currentSelectedFromProps, start, end);
      this.animateLine(this.swipedOverHalfOfContainer(difference) ? nextSelected : currentSelectedFromProps);
    }
  };
  handleTouchEnd = event => {
    const {
      start,
      isSwiping
    } = this.state;
    if (start == null) {
      return;
    }
    const {
      selected
    } = this.props;
    const end = {
      x: event.nativeEvent.changedTouches[0].clientX,
      y: event.nativeEvent.changedTouches[0].clientY,
      time: Date.now()
    };
    const difference = utils.getSwipeDifference(start, end);
    let nextSelected = selected;
    if (isSwiping) {
      if (utils.swipeShouldChangeTab(start, end) || this.swipedOverHalfOfContainer(difference)) {
        nextSelected = this.getTabToSelect(nextSelected, start, end);
      }
      if (nextSelected !== selected) {
        this.switchTab(nextSelected);
      } else {
        this.animateLine(nextSelected);
      }
    }
    this.setState({
      isSwiping: false,
      isScrolling: false
    });
  };
  render() {
    const {
      tabs,
      changeTabOnSwipe,
      name,
      selected,
      className,
      headerWidth
    } = this.props;
    const {
      translateLineX,
      fullWidthTabs
    } = this.state;
    const selectedTab = tabs[selected];
    return /*#__PURE__*/jsxRuntime.jsx(DirectionProvider.DirectionContext.Consumer, {
      children: direction$1 => {
        const isRTL = direction$1 === direction.Direction.RTL;
        return /*#__PURE__*/jsxRuntime.jsxs("div", {
          ref: this.containerReference,
          className: clsx.clsx('tabs', className, {
            'tabs--auto-width': headerWidth === width.Width.AUTO
          }),
          onTouchStart: changeTabOnSwipe ? this.handleTouchStart : undefined,
          onTouchEnd: changeTabOnSwipe ? this.handleTouchEnd : undefined,
          onTouchMove: changeTabOnSwipe ? this.handleTouchMove : undefined,
          children: [/*#__PURE__*/jsxRuntime.jsxs(TabList.default, {
            children: [tabs.map(({
              title,
              disabled
            }, index) => {
              return /*#__PURE__*/jsxRuntime.jsx(Tab.default, {
                ref: node => {
                  this.tabRefs[index] = node;
                },
                id: `${name}-tab-${index}`,
                panelId: `${name}-panel-${index}`,
                selected: selected === index,
                disabled: disabled,
                focusTab: () => {
                  if (this.containerReference.current?.contains(document.activeElement)) {
                    this.tabRefs[index]?.focus();
                  }
                },
                onClick: disabled ? undefined : this.handleTabClick(index),
                onKeyDown: this.onKeyDown(index),
                ...(fullWidthTabs ? {
                  style: {
                    width: `${1 / tabs.length * 100}%`
                  }
                } : {}),
                children: title
              }, title);
            }), translateLineX ? /*#__PURE__*/jsxRuntime.jsx("li", {
              role: "none",
              className: "tabs__line",
              style: {
                width: this.getTabLineWidth(),
                transform: isRTL ? `translateX(-${translateLineX})` : `translateX(${translateLineX})`
              }
            }) : null]
          }), /*#__PURE__*/jsxRuntime.jsx("div", {
            ref: this.setContainerRefAndWidth,
            className: "tabs__panel-container",
            children: selectedTab && !selectedTab.disabled ? /*#__PURE__*/jsxRuntime.jsx(TabPanel.default, {
              tabId: `${name}-tab-${selected}`,
              id: `${name}-panel-${selected}`,
              style: {
                width: '100%'
              },
              children: selectedTab.content
            }, selectedTab.title) : null
          })]
        });
      }
    });
  }
}

exports.default = Tabs;
//# sourceMappingURL=Tabs.js.map
