"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ScrollButtons = exports.default = void 0;

var _AnnounceDecorator = require("@enact/ui/AnnounceDecorator");

var _keymap = require("@enact/core/keymap");

var _propTypes = _interopRequireDefault(require("prop-types"));

var _react = _interopRequireWildcard(require("react"));

var _reactDom = _interopRequireDefault(require("react-dom"));

var _spotlight = _interopRequireWildcard(require("@enact/spotlight"));

var _$L = _interopRequireDefault(require("../internal/$L"));

var _ScrollButton = _interopRequireDefault(require("./ScrollButton"));

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

var nop = function nop() {},
    prepareButton = function prepareButton(isPrev) {
  return function (isVertical) {
    var direction;

    if (isVertical) {
      direction = isPrev ? 'up' : 'down';
    } else {
      direction = isPrev ? 'left' : 'right';
    }

    return 'arrowsmall' + direction;
  };
},
    preparePrevButton = prepareButton(true),
    prepareNextButton = prepareButton(false),
    isPageUp = (0, _keymap.is)('pageUp'),
    isPageDown = (0, _keymap.is)('pageDown');
/**
 * A Moonstone-styled scroll buttons. It is used in [Scrollbar]{@link moonstone/Scrollable.Scrollbar}.
 *
 * @class ScrollButtons
 * @memberof moonstone/Scrollable
 * @ui
 * @private
 */


var ScrollButtons =
/*#__PURE__*/
function (_Component) {
  _inherits(ScrollButtons, _Component);

  function ScrollButtons(props) {
    var _this;

    _classCallCheck(this, ScrollButtons);

    _this = _possibleConstructorReturn(this, (ScrollButtons.__proto__ || Object.getPrototypeOf(ScrollButtons)).call(this, props));
    Object.defineProperty(_assertThisInitialized(_this), "announce", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: null
    });
    Object.defineProperty(_assertThisInitialized(_this), "prevButtonNodeRef", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: null
    });
    Object.defineProperty(_assertThisInitialized(_this), "nextButtonNodeRef", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: null
    });
    Object.defineProperty(_assertThisInitialized(_this), "updateButtons", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(bounds) {
        var vertical = _this.props.vertical,
            currentPos = vertical ? bounds.scrollTop : bounds.scrollLeft,
            maxPos = vertical ? bounds.maxTop : bounds.maxLeft,
            shouldDisablePrevButton = currentPos <= 0,
            shouldDisableNextButton = maxPos - currentPos <= 1;

        _this.setState(function (prevState) {
          var updatePrevButton = prevState.prevButtonDisabled !== shouldDisablePrevButton,
              updateNextButton = prevState.nextButtonDisabled !== shouldDisableNextButton;

          if (updatePrevButton && updateNextButton) {
            return {
              prevButtonDisabled: shouldDisablePrevButton,
              nextButtonDisabled: shouldDisableNextButton
            };
          } else if (updatePrevButton) {
            return {
              prevButtonDisabled: shouldDisablePrevButton
            };
          } else if (updateNextButton) {
            return {
              nextButtonDisabled: shouldDisableNextButton
            };
          }
        });
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "isOneOfScrollButtonsFocused", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value() {
        var current = _spotlight.default.getCurrent();

        return current === _this.prevButtonNodeRef || current === _this.nextButtonNodeRef;
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onDownPrev", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value() {
        if (_this.announce) {
          var _this$props = _this.props,
              rtl = _this$props.rtl,
              vertical = _this$props.vertical;

          _this.announce(vertical && (0, _$L.default)('UP') || rtl && (0, _$L.default)('RIGHT') || (0, _$L.default)('LEFT'));
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onDownNext", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value() {
        if (_this.announce) {
          var _this$props2 = _this.props,
              rtl = _this$props2.rtl,
              vertical = _this$props2.vertical;

          _this.announce(vertical && (0, _$L.default)('DOWN') || rtl && (0, _$L.default)('LEFT') || (0, _$L.default)('RIGHT'));
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onClickPrev", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev) {
        var _this$props3 = _this.props,
            onPrevScroll = _this$props3.onPrevScroll,
            vertical = _this$props3.vertical;
        onPrevScroll(_objectSpread({}, ev, {
          isPreviousScrollButton: true,
          isVerticalScrollBar: vertical
        }));
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onClickNext", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev) {
        var _this$props4 = _this.props,
            onNextScroll = _this$props4.onNextScroll,
            vertical = _this$props4.vertical;
        onNextScroll(_objectSpread({}, ev, {
          isPreviousScrollButton: false,
          isVerticalScrollBar: vertical
        }));
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "focusOnOppositeScrollButton", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev, direction) {
        var buttonNode = ev.target === _this.nextButtonNodeRef ? _this.prevButtonNodeRef : _this.nextButtonNodeRef;
        ev.stopPropagation();

        if (!_spotlight.default.focus(buttonNode)) {
          _spotlight.default.move(direction);
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onSpotlight", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev) {
        var _this$props5 = _this.props,
            focusableScrollButtons = _this$props5.focusableScrollButtons,
            rtl = _this$props5.rtl,
            vertical = _this$props5.vertical,
            target = ev.target; // We don't need to navigate manually if `focusableScrollButtons` is `false`

        if (focusableScrollButtons) {
          var direction = (0, _spotlight.getDirection)(ev.keyCode),
              fromNextToPrev = vertical && direction === 'up' || !vertical && direction === (rtl ? 'right' : 'left'),
              fromPrevToNext = vertical && direction === 'down' || !vertical && direction === (rtl ? 'left' : 'right'); // manually focus the opposite scroll button when 5way pressed

          if (fromNextToPrev && target === _this.nextButtonNodeRef || fromPrevToNext && target === _this.prevButtonNodeRef) {
            _this.focusOnOppositeScrollButton(ev, direction);
          }
        } else {
          // If it is vertical `Scrollable`, move focus to the left for ltr or to the right for rtl
          // If is is horizontal `Scrollable`, move focus to the up
          var _direction = !vertical && 'up' || rtl && 'right' || 'left';

          if (_spotlight.default.getPointerMode()) {
            // When changing from "pointer" mode to "5way key" mode,
            // a pointer is hidden and a last focused item get focused after 30ms.
            // To make sure the content in `VirtualList` or `Scroller` to be focused after that, we used 50ms.
            setTimeout(function () {
              if (_spotlight.default.getCurrent() === target) {
                _spotlight.default.move(_direction);
              }
            }, 50);
          } else if (_spotlight.default.getCurrent() === target) {
            _spotlight.default.move(_direction);
          }
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onKeyDownPrev", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev) {
        var focusableScrollButtons = _this.props.focusableScrollButtons,
            nextButtonDisabled = _this.state.nextButtonDisabled,
            keyCode = ev.keyCode;

        if (isPageDown(keyCode) && !nextButtonDisabled) {
          if (focusableScrollButtons) {
            _spotlight.default.setPointerMode(false);

            _spotlight.default.focus(_this.nextButtonNodeRef);
          } else {
            _this.onClickNext(ev);
          }
        } else if (isPageUp(keyCode)) {
          _this.onClickPrev(ev);
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "onKeyDownNext", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ev) {
        var focusableScrollButtons = _this.props.focusableScrollButtons,
            prevButtonDisabled = _this.state.prevButtonDisabled,
            keyCode = ev.keyCode;

        if (isPageUp(keyCode) && !prevButtonDisabled) {
          if (focusableScrollButtons) {
            _spotlight.default.setPointerMode(false);

            _spotlight.default.focus(_this.prevButtonNodeRef);
          } else {
            _this.onClickPrev(ev);
          }
        } else if (isPageDown(keyCode)) {
          _this.onClickNext(ev);
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "initAnnounceRef", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ref) {
        if (ref) {
          _this.announce = ref.announce;
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "initNextButtonRef", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ref) {
        if (ref) {
          _this.nextButtonNodeRef = _reactDom.default.findDOMNode(ref); // eslint-disable-line react/no-find-dom-node
        }
      }
    });
    Object.defineProperty(_assertThisInitialized(_this), "initPrevButtonRef", {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function value(ref) {
        if (ref) {
          _this.prevButtonNodeRef = _reactDom.default.findDOMNode(ref); // eslint-disable-line react/no-find-dom-node
        }
      }
    });
    _this.state = {
      prevButtonDisabled: true,
      nextButtonDisabled: true
    };
    return _this;
  }

  _createClass(ScrollButtons, [{
    key: "render",
    value: function render() {
      var _props = this.props,
          disabled = _props.disabled,
          nextButtonAriaLabel = _props.nextButtonAriaLabel,
          previousButtonAriaLabel = _props.previousButtonAriaLabel,
          rtl = _props.rtl,
          thumbRenderer = _props.thumbRenderer,
          vertical = _props.vertical,
          _state = this.state,
          prevButtonDisabled = _state.prevButtonDisabled,
          nextButtonDisabled = _state.nextButtonDisabled,
          prevIcon = preparePrevButton(vertical),
          nextIcon = prepareNextButton(vertical);
      return [_react.default.createElement(_ScrollButton.default, {
        "aria-label": rtl && !vertical ? nextButtonAriaLabel : previousButtonAriaLabel,
        "data-spotlight-overflow": "ignore",
        disabled: disabled || prevButtonDisabled,
        key: "prevButton",
        onClick: this.onClickPrev,
        onDown: this.onDownPrev,
        onHoldPulse: this.onClickPrev,
        onKeyDown: this.onKeyDownPrev,
        onSpotlightDown: this.onSpotlight,
        onSpotlightLeft: this.onSpotlight,
        onSpotlightRight: this.onSpotlight,
        onSpotlightUp: this.onSpotlight,
        ref: this.initPrevButtonRef
      }, prevIcon), thumbRenderer(), _react.default.createElement(_ScrollButton.default, {
        "aria-label": rtl && !vertical ? previousButtonAriaLabel : nextButtonAriaLabel,
        "data-spotlight-overflow": "ignore",
        disabled: disabled || nextButtonDisabled,
        key: "nextButton",
        onClick: this.onClickNext,
        onDown: this.onDownNext,
        onHoldPulse: this.onClickNext,
        onKeyDown: this.onKeyDownNext,
        onSpotlightDown: this.onSpotlight,
        onSpotlightLeft: this.onSpotlight,
        onSpotlightRight: this.onSpotlight,
        onSpotlightUp: this.onSpotlight,
        ref: this.initNextButtonRef
      }, nextIcon), _react.default.createElement(_AnnounceDecorator.Announce, {
        key: "announce",
        ref: this.initAnnounceRef
      })];
    }
  }]);

  return ScrollButtons;
}(_react.Component);

exports.ScrollButtons = ScrollButtons;
Object.defineProperty(ScrollButtons, "displayName", {
  configurable: true,
  enumerable: true,
  writable: true,
  value: 'ScrollButtons'
});
Object.defineProperty(ScrollButtons, "propTypes", {
  configurable: true,
  enumerable: true,
  writable: true,
  value:
  /** @lends moonstone/Scrollable.ScrollButtons.prototype */
  {
    /**
     * The render function for thumb.
     *
     * @type {Function}
     * @required
     * @private
     */
    thumbRenderer: _propTypes.default.func.isRequired,

    /**
     * Called to alert the user for accessibility notifications.
     *
     * @type {Function}
     * @public
     */
    announce: _propTypes.default.func,

    /**
     * Specifies to reflect scrollbar's disabled property to the paging controls.
     * When it is `true`, both prev/next buttons are going to be disabled.
     *
     * @type {Boolean}
     * @public
     */
    disabled: _propTypes.default.bool,

    /**
     * When it is `true`, it allows 5 way navigation to the ScrollButtons.
     * This value is set by `Scrollable`.
     *
     * @type {Boolean}
     * @default false
     * @private
     */
    focusableScrollButtons: _propTypes.default.bool,

    /**
    * Sets the hint string read when focusing the next button in the scroll bar.
    *
    * @type {String}
    * @public
    */
    nextButtonAriaLabel: _propTypes.default.string,

    /**
     * Called when the scrollbar's down/right button is pressed.
     *
     * @type {Function}
     * @public
     */
    onNextScroll: _propTypes.default.func,

    /**
     * Called when the scrollbar's up/left button is pressed.
     *
     * @type {Function}
     * @public
     */
    onPrevScroll: _propTypes.default.func,

    /**
     * Sets the hint string read when focusing the previous button in the scroll bar.
     *
     * @type {String}
     * @public
     */
    previousButtonAriaLabel: _propTypes.default.string,

    /**
     * `true` if rtl, `false` if ltr.
     *
     * @type {Boolean}
     * @private
     */
    rtl: _propTypes.default.bool,

    /**
     * The scrollbar will be oriented vertically.
     *
     * @type {Boolean}
     * @default true
     * @public
     */
    vertical: _propTypes.default.bool
  }
});
Object.defineProperty(ScrollButtons, "defaultProps", {
  configurable: true,
  enumerable: true,
  writable: true,
  value: {
    focusableScrollButtons: false,
    onNextScroll: nop,
    onPrevScroll: nop
  }
});
var _default = ScrollButtons;
exports.default = _default;