"use strict";

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

function _react() {
  const data = _interopRequireWildcard(require("react"));

  _react = function () {
    return data;
  };

  return data;
}

function _tslib() {
  const data = require("tslib");

  _tslib = function () {
    return data;
  };

  return data;
}

function _jsxRuntime() {
  const data = require("react/jsx-runtime");

  _jsxRuntime = function () {
    return data;
  };

  return data;
}

function _clsx() {
  const data = _interopRequireDefault(require("clsx"));

  _clsx = function () {
    return data;
  };

  return data;
}

var _utils = require("../utils");

var _useScrollParent = require("../hooks/use-scroll-parent");

var _useEventListener = _interopRequireDefault(require("../hooks/use-event-listener"));

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

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

var _ConfigProviderContext = _interopRequireDefault(require("../config-provider/ConfigProviderContext"));

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

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

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

const DEFAULT_HEAD_HEIGHT = 50;
const TEXT_STATUS = ['pulling', 'loosing', 'success'];

const PullRefresh = props => {
  const {
    prefixCls,
    createNamespace,
    locale
  } = (0, _react().useContext)(_ConfigProviderContext.default);
  const [bem] = createNamespace('pull-refresh', prefixCls);
  const {
    disabled,
    animationDuration
  } = props;
  const root = (0, _react().useRef)();
  const [state, updateState] = (0, _hooks.useSetState)({
    refreshing: false,
    status: 'normal',
    distance: 0,
    duration: 0
  });
  const track = (0, _react().useRef)();
  const reachTop = (0, _react().useRef)(null);
  const touch = (0, _hooks.useTouch)();

  const getHeadStyle = () => {
    if (props.headHeight !== DEFAULT_HEAD_HEIGHT) {
      return {
        height: `${props.headHeight}px`
      };
    }

    return null;
  };

  const isTouchable = (0, _react().useCallback)(() => {
    return state.status !== 'loading' && state.status !== 'success' && !disabled;
  }, [state.status, disabled]);

  const ease = distance => {
    const pullDistance = +(props.pullDistance || props.headHeight);

    if (distance > pullDistance) {
      if (distance < pullDistance * 2) {
        distance = pullDistance + (distance - pullDistance) / 2;
      } else {
        distance = pullDistance * 1.5 + (distance - pullDistance * 2) / 4;
      }
    }

    return Math.round(distance);
  };

  const setStatus = (distance, isLoading) => {
    const pullDistance = +(props.pullDistance || props.headHeight);
    const newState = {
      distance
    };

    if (isLoading) {
      newState.status = 'loading';
    } else if (distance === 0) {
      newState.status = 'normal';
    } else if (distance < pullDistance) {
      newState.status = 'pulling';
    } else {
      newState.status = 'loosing';
    }

    updateState(newState);
  };

  const getStatusText = () => {
    if (state.status === 'normal') {
      return '';
    }

    return props[`${state.status}Text`] || locale.vanPullRefresh[state.status];
  };

  const renderStatus = () => {
    var _a;

    const {
      status,
      distance
    } = state;

    if (typeof props[`${state.status}Text`] === 'function') {
      return (_a = props[`${state.status}Text`]) === null || _a === void 0 ? void 0 : _a.call(props, {
        distance
      });
    }

    const nodes = [];

    if (TEXT_STATUS.includes(status)) {
      nodes.push((0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('text'))
      }, {
        children: getStatusText()
      }), "text"));
    }

    if (status === 'loading') {
      nodes.push((0, _jsxRuntime().jsx)(_loading.default, Object.assign({
        className: (0, _clsx().default)(bem('loading'))
      }, {
        children: getStatusText()
      }), "loading"));
    }

    return nodes;
  };

  const showSuccessTip = () => {
    updateState({
      status: 'success'
    });
    setTimeout(() => {
      setStatus(0);
    }, +props.successDuration);
  };

  const onRefresh = () => (0, _tslib().__awaiter)(void 0, void 0, void 0, function* () {
    try {
      updateState({
        refreshing: true
      });
      yield props.onRefresh();
      updateState({
        refreshing: false
      });
    } catch (error) {
      updateState({
        refreshing: false
      });
    }
  });

  const checkPosition = event => {
    const scrollTarget = (0, _useScrollParent.getScrollParent)(event.target);
    reachTop.current = (0, _utils.getScrollTop)(scrollTarget) === 0;

    if (reachTop.current) {
      updateState({
        duration: 0
      });
      touch.start(event);
    }
  };

  const onTouchStart = event => {
    if (isTouchable()) {
      checkPosition(event.nativeEvent);
    }
  };

  const onTouchMove = (0, _react().useCallback)(event => {
    if (isTouchable()) {
      if (!reachTop.current) {
        checkPosition(event);
      }

      touch.move(event);

      if (reachTop.current && touch.deltaY.current >= 0 && touch.isVertical()) {
        setStatus(ease(touch.deltaY.current));
        (0, _utils.preventDefault)(event);
      } else {
        /**
         * IN THIS CASE:
         * if component don't rerender after event.preventDefault
         * ios will hold `preventDefault` behavior when touchmoving
         * it will cause window unscrollable
         */
        setStatus(0);
      }
    }
  }, // eslint-disable-next-line react-hooks/exhaustive-deps
  [reachTop.current, touch.deltaY.current, isTouchable]);

  const onTouchEnd = () => {
    if (reachTop.current && touch.deltaY && isTouchable()) {
      updateState({
        duration: +animationDuration
      });

      if (state.status === 'loosing') {
        setStatus(+props.headHeight, true);
        onRefresh();
      } else {
        setStatus(0);
      }
    }
  };

  (0, _useEventListener.default)('touchmove', onTouchMove, {
    target: track.current,
    depends: [reachTop.current, isTouchable(), touch.deltaY]
  });
  (0, _hooks.useUpdateEffect)(() => {
    updateState({
      duration: +animationDuration
    });

    if (state.refreshing) {
      setStatus(+props.headHeight, true);
    } else if (props.successText) {
      showSuccessTip();
    } else {
      setStatus(0, false);
    }
  }, [state.refreshing]);
  const trackStyle = (0, _react().useMemo)(() => ({
    transitionDuration: `${state.duration}ms`,
    transform: state.distance ? `translate3d(0,${state.distance}px, 0)` : ''
  }), [state.duration, state.distance]);
  return (0, _jsxRuntime().jsx)("div", Object.assign({
    ref: root,
    className: (0, _clsx().default)(props.className, bem()),
    style: props.style
  }, {
    children: (0, _jsxRuntime().jsxs)("div", Object.assign({
      ref: track,
      className: (0, _clsx().default)(bem('track')),
      style: trackStyle,
      onTouchStart: onTouchStart,
      onTouchEnd: onTouchEnd,
      onTouchCancel: onTouchEnd
    }, {
      children: [(0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('head')),
        style: getHeadStyle()
      }, {
        children: renderStatus()
      })), props.children]
    }))
  }));
};

PullRefresh.defaultProps = {
  headHeight: 50,
  animationDuration: 300,
  successDuration: 500
};
var _default = PullRefresh;
exports.default = _default;