"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

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

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));

var _react = require("@use-gesture/react");

var _bem = require("@zarm-design/bem");

var _icons = require("@zarm-design/icons");

var _throttle = _interopRequireDefault(require("lodash/throttle"));

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

var _configProvider = require("../config-provider");

var _loading = _interopRequireDefault(require("../loading"));

var _dom = require("../utils/dom");

var _events = _interopRequireDefault(require("../utils/events"));

var _hooks = require("../utils/hooks");

var _interface = require("./interface");

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

var Pull = /*#__PURE__*/_react2.default.forwardRef(function (props, ref) {
  var _props$load;

  var pullRef = ref || /*#__PURE__*/_react2.default.createRef();

  var wrap = (0, _react2.useRef)();

  var _useState = (0, _react2.useState)(false),
      _useState2 = (0, _slicedToArray2.default)(_useState, 2),
      isMounted = _useState2[0],
      setIsMounted = _useState2[1];

  var _useState3 = (0, _react2.useState)(0),
      _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
      offsetY = _useState4[0],
      setOffsetY = _useState4[1];

  var _useState5 = (0, _react2.useState)(0),
      _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
      animationDuration = _useState6[0],
      setAnimationDuration = _useState6[1];

  var _useState7 = (0, _react2.useState)(props.refresh.state),
      _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
      refreshState = _useState8[0],
      setRefreshState = _useState8[1];

  var _useState9 = (0, _react2.useState)(props.load.state),
      _useState10 = (0, _slicedToArray2.default)(_useState9, 2),
      loadState = _useState10[0],
      setLoadState = _useState10[1];

  var prevLoad = (0, _react2.useRef)({});
  var prevRefresh = (0, _react2.useRef)({});

  var _React$useContext = _react2.default.useContext(_configProvider.ConfigContext),
      prefixCls = _React$useContext.prefixCls,
      locale = _React$useContext.locale;

  var bem = (0, _bem.createBEM)('pull', {
    prefixCls: prefixCls
  });
  var onScroll = (0, _hooks.useEventCallback)(function () {
    // window为滚动容器时，无法通过 window 直接取到 scrollHeight 和 clientHeight。
    var _ref = wrap.current,
        _ref$scrollHeight = _ref.scrollHeight,
        scrollHeight = _ref$scrollHeight === void 0 ? document.body.clientHeight : _ref$scrollHeight,
        _ref$clientHeight = _ref.clientHeight,
        clientHeight = _ref$clientHeight === void 0 ? document.documentElement.clientHeight : _ref$clientHeight;

    var load = _objectSpread(_objectSpread({}, Pull.defaultProps.load), props.load);

    var handler = load.handler,
        distance = load.distance;

    if (refreshState !== _interface.REFRESH_STATE.normal || loadState !== _interface.LOAD_STATE.normal || scrollHeight <= clientHeight || // 内容高度 - 偏移值 - 修正距离 <= 容器可见高度‚
    scrollHeight - (0, _dom.getScrollTop)(wrap.current) - distance > clientHeight) {
      return;
    }

    handler === null || handler === void 0 ? void 0 : handler();
  }, [props === null || props === void 0 ? void 0 : (_props$load = props.load) === null || _props$load === void 0 ? void 0 : _props$load.handler]);
  var throttledScroll = (0, _throttle.default)(onScroll, 250);

  var setScrollParent = function setScrollParent() {
    var _scrollContainer = (0, _dom.getScrollParent)(pullRef.current); // scrollContainer 未变更


    if (wrap.current === _scrollContainer) return; // 重新获取 scrollContainer

    wrap.current = _scrollContainer;
  };

  (0, _react2.useEffect)(function () {
    setScrollParent();
  });
  (0, _react2.useEffect)(function () {
    _events.default.on(wrap.current, 'scroll', throttledScroll);

    return function () {
      _events.default.off(wrap.current, 'scroll', throttledScroll);
    };
  }, [wrap.current]);
  /**
   * 执行动画
   * @param  {number} options.offsetY  偏移距离
   * @param  {number} options.animationDuration 动画执行时间
   */

  var doTransition = function doTransition(_ref2) {
    var iOffsetY = _ref2.offsetY,
        iAnimationDuration = _ref2.animationDuration;
    setOffsetY(iOffsetY);
    setAnimationDuration(iAnimationDuration);
  };
  /**
   * 执行加载动作
   * @param  {LOAD_STATE} iLoadState 加载状态
   */


  var doLoadAction = function doLoadAction(iLoadState) {
    var stayTime = props.stayTime;
    setLoadState(iLoadState);

    switch (iLoadState) {
      case _interface.LOAD_STATE.success:
        doLoadAction(_interface.LOAD_STATE.normal);
        break;

      case _interface.LOAD_STATE.failure:
        setTimeout(function () {
          if (!isMounted) return;
          doLoadAction(_interface.LOAD_STATE.abort);
        }, stayTime);
        break;

      default:
    }
  };
  /**
   * 执行刷新动作
   * @param  {REFRESH_STATE} iRefreshState 刷新状态
   * @param  {number}        iOffsetY      偏移距离
   */


  var doRefreshAction = function doRefreshAction(iRefreshState, iOffsetY) {
    var stayTime = props.stayTime;
    setRefreshState(iRefreshState);

    switch (iRefreshState) {
      case _interface.REFRESH_STATE.pull:
      case _interface.REFRESH_STATE.drop:
        doTransition({
          offsetY: iOffsetY,
          animationDuration: 0
        });
        break;

      case _interface.REFRESH_STATE.loading:
        doTransition({
          offsetY: 'auto',
          animationDuration: animationDuration
        });
        break;

      case _interface.REFRESH_STATE.success:
      case _interface.REFRESH_STATE.failure:
        doTransition({
          offsetY: 'auto',
          animationDuration: animationDuration
        });
        setTimeout(function () {
          if (!isMounted) return;
          doRefreshAction(_interface.REFRESH_STATE.normal);
          doLoadAction(_interface.LOAD_STATE.normal);
        }, stayTime);
        break;

      default:
        doTransition({
          offsetY: 0,
          animationDuration: props.animationDuration
        });
    }
  };

  var onDragMove = function onDragMove(state) {
    var _Pull$defaultProps;

    var movement = state.movement,
        event = state.event;

    var _movement = (0, _slicedToArray2.default)(movement, 2),
        dragOffsetY = _movement[1];

    var _ref3 = props.refresh,
        handler = _ref3.handler;

    if ( // 未设置刷新事件
    !handler || // 上拉
    dragOffsetY <= 0 || // 未滚动到顶部
    dragOffsetY > 0 && (0, _dom.getScrollTop)(wrap.current) > 0 || // 已经触发过加载状态
    refreshState >= _interface.REFRESH_STATE.loading) {
      return false;
    }

    if (event.cancelable) {
      event.preventDefault();
    }

    var refresh = _objectSpread(_objectSpread({}, (_Pull$defaultProps = Pull.defaultProps) === null || _Pull$defaultProps === void 0 ? void 0 : _Pull$defaultProps.refresh), props === null || props === void 0 ? void 0 : props.refresh);

    var startDistance = refresh.startDistance,
        distance = refresh.distance; // 设置拖动距离衰减（实际下拉移动距离为拖动距离的1/3）

    var offset = state.movement[1] / 3; // 判断是否达到释放立即刷新的条件

    var action = offset - startDistance < distance ? _interface.REFRESH_STATE.pull : _interface.REFRESH_STATE.drop;
    doRefreshAction(action, offset);
    return true;
  };

  var onDragEnd = function onDragEnd(_ref4) {
    var iOffsetY = _ref4.offsetY;

    // 没有产生位移
    if (!iOffsetY) {
      return;
    } // 当前状态为下拉状态时


    if (refreshState === _interface.REFRESH_STATE.pull) {
      doRefreshAction(_interface.REFRESH_STATE.normal);
      return;
    } // 执行外部触发刷新的回调


    var _ref5 = props.refresh,
        handler = _ref5.handler;
    handler === null || handler === void 0 ? void 0 : handler();
  };

  var bind = (0, _react.useDrag)(function (state) {
    if (state.last) {
      setAnimationDuration(props.animationDuration);
      onDragEnd({
        offsetY: offsetY
      });
      return;
    }

    onDragMove(state);
  }, {
    enabled: true,
    pointer: {
      touch: true
    },
    axis: 'y',
    eventOptions: {
      passive: !_events.default.supportsPassiveEvents
    }
  });
  var load = props.load,
      refresh = props.refresh;

  if (prevLoad.current.state !== load.state) {
    doLoadAction(load.state);
    prevLoad.current = load;
  }

  if (prevRefresh.current.state !== refresh.state) {
    doRefreshAction(refresh.state);
    prevRefresh.current = refresh;
  }

  (0, _react2.useEffect)(function () {
    setIsMounted(true);
    pullRef.current && _events.default.on(pullRef.current, 'touchmove', function () {});
    return function () {
      pullRef.current && _events.default.off(pullRef.current, 'touchmove', function () {});
      setIsMounted(false);
    };
  }, []);
  /**
   * 渲染刷新节点
   */

  var renderRefresh = function renderRefresh() {
    var _Pull$defaultProps2;

    var refreshProps = _objectSpread(_objectSpread({}, (_Pull$defaultProps2 = Pull.defaultProps) === null || _Pull$defaultProps2 === void 0 ? void 0 : _Pull$defaultProps2.refresh), props === null || props === void 0 ? void 0 : props.refresh);

    var startDistance = refreshProps.startDistance,
        distance = refreshProps.distance,
        render = refreshProps.render;
    var percent = 0;

    if (typeof offsetY === 'number' && offsetY >= startDistance) {
      percent = (offsetY - startDistance < distance ? offsetY - startDistance : distance) * 100 / distance;
    }

    if (typeof render === 'function') {
      return render(refreshState, percent);
    }

    var refreshCls = bem('control');

    switch (refreshState) {
      case _interface.REFRESH_STATE.pull:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: refreshCls
        }, /*#__PURE__*/_react2.default.createElement(_loading.default, {
          loading: false,
          percent: percent
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.pullText));

      case _interface.REFRESH_STATE.drop:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: refreshCls
        }, /*#__PURE__*/_react2.default.createElement(_loading.default, {
          loading: false,
          percent: 100
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.dropText));

      case _interface.REFRESH_STATE.loading:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: refreshCls
        }, /*#__PURE__*/_react2.default.createElement(_loading.default, {
          type: "spinner"
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.loadingText));

      case _interface.REFRESH_STATE.success:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: refreshCls
        }, /*#__PURE__*/_react2.default.createElement(_icons.SuccessCircle, {
          theme: "success"
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.successText));

      case _interface.REFRESH_STATE.failure:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: refreshCls
        }, /*#__PURE__*/_react2.default.createElement(_icons.WarningCircle, {
          theme: "danger"
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.failureText));

      default:
    }
  };
  /**
   * 渲染加载节点
   */


  var renderLoad = function renderLoad() {
    var _Pull$defaultProps3;

    var loadProps = _objectSpread(_objectSpread({}, (_Pull$defaultProps3 = Pull.defaultProps) === null || _Pull$defaultProps3 === void 0 ? void 0 : _Pull$defaultProps3.load), props === null || props === void 0 ? void 0 : props.load);

    var render = loadProps.render;

    if (typeof render === 'function') {
      return render(loadState);
    }

    var loadCls = bem('control');

    switch (loadState) {
      case _interface.LOAD_STATE.loading:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: loadCls
        }, /*#__PURE__*/_react2.default.createElement(_loading.default, {
          type: "spinner"
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.loadingText));

      case _interface.LOAD_STATE.failure:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: loadCls
        }, /*#__PURE__*/_react2.default.createElement(_icons.WarningCircle, {
          theme: "danger"
        }), /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.failureText));

      case _interface.LOAD_STATE.complete:
        return /*#__PURE__*/_react2.default.createElement("div", {
          className: loadCls
        }, /*#__PURE__*/_react2.default.createElement("span", null, locale.Pull.completeText));

      default:
    }
  };

  var className = props.className,
      style = props.style,
      children = props.children;
  var cls = bem([className]);
  var loadCls = bem('load', [{
    show: loadState >= _interface.LOAD_STATE.loading
  }]);
  var contentStyle = {
    WebkitTransition: "all ".concat(animationDuration, "ms"),
    transition: "all ".concat(animationDuration, "ms")
  };

  if (refreshState <= _interface.REFRESH_STATE.drop) {
    contentStyle.WebkitTransform = "translate3d(0, ".concat(offsetY, "px, 0)");
    contentStyle.transform = "translate3d(0, ".concat(offsetY, "px, 0)");
  }

  return /*#__PURE__*/_react2.default.createElement("div", (0, _extends2.default)({
    className: cls,
    style: style
  }, bind(), {
    ref: pullRef
  }), /*#__PURE__*/_react2.default.createElement("div", {
    className: bem('content'),
    style: contentStyle
  }, /*#__PURE__*/_react2.default.createElement("div", {
    className: bem('refresh')
  }, renderRefresh()), /*#__PURE__*/_react2.default.createElement("div", {
    className: bem('body')
  }, children), /*#__PURE__*/_react2.default.createElement("div", {
    className: loadCls
  }, renderLoad())));
});

Pull.defaultProps = {
  refresh: {
    state: _interface.REFRESH_STATE.normal,
    startDistance: 30,
    distance: 30
  },
  load: {
    state: _interface.LOAD_STATE.normal,
    distance: 0
  },
  animationDuration: 400,
  stayTime: 1000
};
var _default = Pull;
exports.default = _default;