"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Swiper = void 0;
var _web = require("@react-spring/web");
var _react = require("@use-gesture/react");
var _ahooks = require("ahooks");
var _classnames = _interopRequireDefault(require("classnames"));
var _toArray = _interopRequireDefault(require("rc-util/lib/Children/toArray"));
var _react2 = _interopRequireWildcard(require("react"));
var _stagedComponents = require("staged-components");
var _bound = require("../../utils/bound");
var _devLog = require("../../utils/dev-log");
var _nativeProps = require("../../utils/native-props");
var _useRefState = require("../../utils/use-ref-state");
var _withDefaultProps = require("../../utils/with-default-props");
var _withFuncProps = require("../../utils/with-func-props");
var _pageIndicator = _interopRequireDefault(require("../page-indicator"));
var _swiperItem = require("./swiper-item");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const classPrefix = `adm-swiper`;
const eventToPropRecord = {
  'mousedown': 'onMouseDown',
  'mousemove': 'onMouseMove',
  'mouseup': 'onMouseUp'
};
const defaultProps = {
  defaultIndex: 0,
  allowTouchMove: true,
  autoplay: false,
  autoplayInterval: 3000,
  loop: false,
  direction: 'horizontal',
  slideSize: 100,
  trackOffset: 0,
  stuckAtBoundary: true,
  rubberband: true,
  stopPropagation: []
};
let currentUid;
const Swiper = exports.Swiper = (0, _react2.forwardRef)((0, _stagedComponents.staged)((p, ref) => {
  const props = (0, _withDefaultProps.mergeProps)(defaultProps, p);
  const {
    direction,
    total,
    children,
    indicator
  } = props;
  const [uid] = (0, _react2.useState)({});
  const timeoutRef = (0, _react2.useRef)(null);
  const isVertical = direction === 'vertical';
  const slideRatio = props.slideSize / 100;
  const offsetRatio = props.trackOffset / 100;
  const {
    validChildren,
    count,
    renderChildren
  } = (0, _react2.useMemo)(() => {
    let count = 0;
    let renderChildren = undefined;
    let validChildren = undefined;
    if (typeof children === 'function') {
      renderChildren = children;
    } else {
      const childrenArray = (0, _toArray.default)(children);
      validChildren = childrenArray.filter(child => {
        if (!_react2.default.isValidElement(child)) return null;
        if (child.type !== _swiperItem.SwiperItem) {
          (0, _devLog.devWarning)('Swiper', 'The children of `Swiper` must be `Swiper.Item` components.');
          return false;
        }
        count++;
        return true;
      });
    }
    return {
      renderChildren,
      validChildren,
      count
    };
  }, [children]);
  const mergedTotal = total !== null && total !== void 0 ? total : count;
  if (mergedTotal === 0 || !validChildren && !renderChildren) {
    (0, _devLog.devWarning)('Swiper', '`Swiper` needs at least one child.');
    return null;
  }
  return () => {
    let loop = props.loop;
    if (slideRatio * (mergedTotal - 1) < 1) {
      loop = false;
    }
    const trackRef = (0, _react2.useRef)(null);
    function getSlidePixels() {
      const track = trackRef.current;
      if (!track) return 0;
      const trackPixels = isVertical ? track.offsetHeight : track.offsetWidth;
      return trackPixels * props.slideSize / 100;
    }
    const [current, setCurrent, getCurrent] = (0, _ahooks.useGetState)(props.defaultIndex);
    const [dragging, setDragging, draggingRef] = (0, _useRefState.useRefState)(false);
    function boundIndex(current) {
      let min = 0;
      let max = mergedTotal - 1;
      if (props.stuckAtBoundary) {
        min += offsetRatio / slideRatio;
        max -= (1 - slideRatio - offsetRatio) / slideRatio;
      }
      return (0, _bound.bound)(current, min, max);
    }
    const [{
      position
    }, api] = (0, _web.useSpring)(() => ({
      position: boundIndex(current) * 100,
      config: {
        tension: 200,
        friction: 30
      },
      onRest: () => {
        if (draggingRef.current) return;
        if (!loop) return;
        const rawX = position.get();
        const totalWidth = 100 * mergedTotal;
        const standardPosition = modulus(rawX, totalWidth);
        if (standardPosition === rawX) return;
        api.start({
          position: standardPosition,
          immediate: true
        });
      }
    }), [mergedTotal]);
    const dragCancelRef = (0, _react2.useRef)(null);
    function forceCancelDrag() {
      var _a;
      (_a = dragCancelRef.current) === null || _a === void 0 ? void 0 : _a.call(dragCancelRef);
      draggingRef.current = false;
    }
    const bind = (0, _react.useDrag)(state => {
      dragCancelRef.current = state.cancel;
      if (!state.intentional) return;
      if (state.first && !currentUid) {
        currentUid = uid;
      }
      if (currentUid !== uid) return;
      currentUid = state.last ? undefined : uid;
      const slidePixels = getSlidePixels();
      if (!slidePixels) return;
      const paramIndex = isVertical ? 1 : 0;
      const offset = state.offset[paramIndex];
      const direction = state.direction[paramIndex];
      const velocity = state.velocity[paramIndex];
      setDragging(true);
      if (!state.last) {
        api.start({
          position: offset * 100 / slidePixels,
          immediate: true
        });
      } else {
        const minIndex = Math.floor(offset / slidePixels);
        const maxIndex = minIndex + 1;
        const index = Math.round((offset + velocity * 2000 * direction) / slidePixels);
        swipeTo((0, _bound.bound)(index, minIndex, maxIndex));
        window.setTimeout(() => {
          setDragging(false);
        });
      }
    }, {
      transform: ([x, y]) => [-x, -y],
      from: () => {
        const slidePixels = getSlidePixels();
        return [position.get() / 100 * slidePixels, position.get() / 100 * slidePixels];
      },
      triggerAllEvents: true,
      bounds: () => {
        if (loop) return {};
        const slidePixels = getSlidePixels();
        const lowerBound = boundIndex(0) * slidePixels;
        const upperBound = boundIndex(mergedTotal - 1) * slidePixels;
        return isVertical ? {
          top: lowerBound,
          bottom: upperBound
        } : {
          left: lowerBound,
          right: upperBound
        };
      },
      rubberband: props.rubberband,
      axis: isVertical ? 'y' : 'x',
      preventScroll: !isVertical,
      pointer: {
        touch: true
      }
    });
    function swipeTo(index, immediate = false) {
      var _a;
      const roundedIndex = Math.round(index);
      const targetIndex = loop ? modulus(roundedIndex, mergedTotal) : (0, _bound.bound)(roundedIndex, 0, mergedTotal - 1);
      if (targetIndex !== getCurrent()) {
        (_a = props.onIndexChange) === null || _a === void 0 ? void 0 : _a.call(props, targetIndex);
      }
      setCurrent(targetIndex);
      api.start({
        position: (loop ? roundedIndex : boundIndex(roundedIndex)) * 100,
        immediate
      });
    }
    function swipeNext() {
      swipeTo(Math.round(position.get() / 100) + 1);
    }
    function swipePrev() {
      swipeTo(Math.round(position.get() / 100) - 1);
    }
    (0, _react2.useImperativeHandle)(ref, () => ({
      swipeTo,
      swipeNext,
      swipePrev
    }));
    (0, _ahooks.useIsomorphicLayoutEffect)(() => {
      const maxIndex = mergedTotal - 1;
      if (current > maxIndex) {
        swipeTo(maxIndex, true);
      }
    });
    const {
      autoplay,
      autoplayInterval
    } = props;
    const runTimeSwiper = () => {
      timeoutRef.current = window.setTimeout(() => {
        if (autoplay === 'reverse') {
          swipePrev();
        } else {
          swipeNext();
        }
        runTimeSwiper();
      }, autoplayInterval);
    };
    (0, _react2.useEffect)(() => {
      if (!autoplay || dragging) return;
      runTimeSwiper();
      return () => {
        if (timeoutRef.current) window.clearTimeout(timeoutRef.current);
      };
    }, [autoplay, autoplayInterval, dragging, mergedTotal]);
    // ============================== Render ==============================
    // Render Item
    function renderItem(index, child, key) {
      let itemStyle = {};
      if (loop) {
        itemStyle = {
          [isVertical ? 'y' : 'x']: position.to(position => {
            let finalPosition = -position + index * 100;
            const totalWidth = mergedTotal * 100;
            const flagWidth = totalWidth / 2;
            finalPosition = modulus(finalPosition + flagWidth, totalWidth) - flagWidth;
            return `${finalPosition}%`;
          }),
          [isVertical ? 'top' : 'left']: `-${index * 100}%`
        };
      }
      return _react2.default.createElement(_web.animated.div, {
        className: (0, _classnames.default)(`${classPrefix}-slide`, {
          [`${classPrefix}-slide-active`]: current === index
        }),
        style: itemStyle,
        key: key !== null && key !== void 0 ? key : index
      }, child);
    }
    const renderStableItems = () => {
      if (renderChildren && total) {
        const offsetCount = 2;
        const startIndex = Math.max(current - offsetCount, 0);
        const endIndex = Math.min(current + offsetCount, total - 1);
        const items = [];
        for (let index = startIndex; index <= endIndex; index += 1) {
          items.push(renderItem(index, renderChildren(index)));
        }
        return _react2.default.createElement(_react2.default.Fragment, null, _react2.default.createElement("div", {
          className: `${classPrefix}-slide-placeholder`,
          style: {
            [isVertical ? 'height' : 'width']: `${startIndex * 100}%`
          }
        }), items);
      }
      if (validChildren) {
        return validChildren.map((child, index) => {
          var _a;
          return renderItem(index, child, (_a = child === null || child === void 0 ? void 0 : child.key) !== null && _a !== void 0 ? _a : index);
        });
      }
      return null;
    };
    function renderItems() {
      return renderStableItems();
    }
    // Render Track Inner
    function renderTrackInner() {
      if (loop) {
        return _react2.default.createElement("div", {
          className: `${classPrefix}-track-inner`
        }, renderItems());
      } else {
        return _react2.default.createElement(_web.animated.div, {
          className: `${classPrefix}-track-inner`,
          style: {
            [isVertical ? 'y' : 'x']: position.to(position => `${-position}%`)
          }
        }, renderItems());
      }
    }
    // Render
    const style = {
      '--slide-size': `${props.slideSize}%`,
      '--track-offset': `${props.trackOffset}%`
    };
    const dragProps = Object.assign({}, props.allowTouchMove ? bind() : {});
    const stopPropagationProps = {};
    for (const key of props.stopPropagation) {
      const prop = eventToPropRecord[key];
      stopPropagationProps[prop] = function (e) {
        e.stopPropagation();
      };
    }
    const mergedProps = (0, _withFuncProps.mergeFuncProps)(dragProps, stopPropagationProps);
    let indicatorNode = null;
    if (typeof indicator === 'function') {
      indicatorNode = indicator(mergedTotal, current);
    } else if (indicator !== false) {
      indicatorNode = _react2.default.createElement("div", {
        className: `${classPrefix}-indicator`
      }, _react2.default.createElement(_pageIndicator.default, Object.assign({}, props.indicatorProps, {
        total: mergedTotal,
        current: current,
        direction: direction
      })));
    }
    return (0, _nativeProps.withNativeProps)(props, _react2.default.createElement("div", {
      className: (0, _classnames.default)(classPrefix, `${classPrefix}-${direction}`),
      style: style
    }, _react2.default.createElement("div", Object.assign({
      ref: trackRef,
      className: (0, _classnames.default)(`${classPrefix}-track`, {
        [`${classPrefix}-track-allow-touch-move`]: props.allowTouchMove
      }),
      onClickCapture: e => {
        if (draggingRef.current) {
          e.stopPropagation();
        }
        forceCancelDrag();
      }
    }, mergedProps), renderTrackInner()), indicatorNode));
  };
}));
function modulus(value, division) {
  const remainder = value % division;
  return remainder < 0 ? remainder + division : remainder;
}