"use strict";

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

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

  _jsxRuntime = function () {
    return data;
  };

  return data;
}

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

  _react = function () {
    return data;
  };

  return data;
}

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

  _clsx = function () {
    return data;
  };

  return data;
}

function _web() {
  const data = require("@react-spring/web");

  _web = function () {
    return data;
  };

  return data;
}

function _react2() {
  const data = require("@use-gesture/react");

  _react2 = function () {
    return data;
  };

  return data;
}

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

var _SwiperItem = _interopRequireDefault(require("./SwiperItem"));

var _useRefs = _interopRequireDefault(require("../hooks/use-refs"));

var _useRefState = _interopRequireDefault(require("../hooks/use-ref-state"));

var _bound = require("../utils/bound");

var _devLog = require("../utils/dev-log");

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

var _SwiperPagIndicator = _interopRequireDefault(require("./SwiperPagIndicator"));

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

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 Swiper = (0, _react().forwardRef)((props, ref) => {
  const {
    prefixCls,
    createNamespace
  } = (0, _react().useContext)(_ConfigProviderContext.default);
  const [bem] = createNamespace('swiper', prefixCls);
  const {
    loop: outerLoop,
    autoplay,
    vertical,
    duration,
    autoHeight
  } = props;
  const axis = vertical ? 'y' : 'x';
  const slideRatio = props.slideSize / 100;
  const offsetRatio = props.trackOffset / 100;
  const {
    validChildren,
    count
  } = (0, _react().useMemo)(() => {
    let innerCount = 0;

    const innerValidChildren = _react().default.Children.map(props.children, child => {
      if (!_react().default.isValidElement(child)) return null;

      if (child.type !== _SwiperItem.default) {
        (0, _devLog.devWarning)('Swiper', 'The children of `Swiper` must be `Swiper.Item` components.');
        return null;
      }

      innerCount++;
      return child;
    });

    return {
      validChildren: innerValidChildren,
      count: innerCount
    };
  }, [props.children]);
  const trackRef = (0, _react().useRef)(null);
  const [childrenRefs, setChildrenRefs] = (0, _useRefs.default)();
  const [enabled, setEnabled] = (0, _react().useState)(() => props.enabled);
  const [current, setCurrent] = (0, _react().useState)(props.initialSwipe);
  const [dragging, setDragging, draggingRef] = (0, _useRefState.default)(false);
  const computedStyle = (0, _react().useMemo)(() => {
    return Object.assign({
      [`--${prefixCls}-swipe-slide-size`]: `${props.slideSize}%`,
      [`--${prefixCls}-swipe-track-offset`]: `${props.trackOffset}%`
    }, props.style);
  }, [prefixCls, props.slideSize, props.trackOffset, props.style]);
  const trackStyle = (0, _react().useMemo)(() => {
    if (!autoHeight) return {};
    const target = childrenRefs[current];
    if (target) return {
      height: target.getHeight() || 'auto'
    };
    return {}; // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoHeight, childrenRefs.length, current]);
  const loop = (0, _react().useMemo)(() => {
    if (slideRatio * (count - 1) < 1) return false;
    return outerLoop;
  }, [count, outerLoop, slideRatio]);

  const getSlidePixels = () => {
    const track = trackRef.current;
    if (!track) return 0;
    const trackPixels = vertical ? track.offsetHeight : track.offsetWidth;
    return trackPixels * props.slideSize / 100;
  };

  const boundIndex = cur => {
    let min = 0;
    let max = count - 1;

    if (props.stuckAtBoundary) {
      min += (1 - slideRatio - offsetRatio) / slideRatio;
      max -= (1 - slideRatio - offsetRatio) / slideRatio;
    }

    return (0, _bound.bound)(cur, min, max);
  };

  const [{
    position
  }, api] = (0, _web().useSpring)(() => ({
    position: boundIndex(current) * 100,
    config: {
      tension: 200,
      friction: 30,
      duration
    },
    onRest: () => {
      if (draggingRef.current) return;
      if (!loop) return;
      const rawX = position.get();
      const totalWidth = 100 * count;
      const standardPosition = modulus(rawX, totalWidth);
      if (standardPosition === rawX) return;
      api.start({
        position: standardPosition,
        immediate: true
      });
    }
  }), [count]);
  const bind = (0, _react2().useDrag)(state => {
    var _a;

    const slidePixels = getSlidePixels();
    if (!slidePixels) return;

    if (!props.preventScroll && isScrollTarget(state.target, (_a = childrenRefs[current]) === null || _a === void 0 ? void 0 : _a.self)) {
      return;
    }

    const paramIndex = vertical ? 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 index = Math.round((offset + Math.min(velocity * 2000, slidePixels) * direction) / slidePixels);
      swipeTo(index);
      window.setTimeout(() => {
        setDragging(false);
      });
    }
  }, {
    enabled,
    transform: ([x, y]) => [-x, -y],
    from: () => {
      const slidePixels = getSlidePixels();
      return [position.get() / 100 * slidePixels, position.get() / 100 * slidePixels];
    },
    bounds: () => {
      if (loop) return {};
      const slidePixels = getSlidePixels();
      const lowerBound = boundIndex(0) * slidePixels;
      const upperBound = boundIndex(count - 1) * slidePixels;
      return vertical ? {
        top: lowerBound,
        bottom: upperBound
      } : {
        left: lowerBound,
        right: upperBound
      };
    },
    rubberband: props.rubberband,
    axis,
    preventScroll: axis === 'x' ? props.preventScroll : false,
    pointer: {
      touch: true
    }
  });

  const renderIndicator = () => {
    if (props.indicator === undefined || props.indicator === true) {
      return (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('indicator', {
          vertical
        }))
      }, {
        children: (0, _jsxRuntime().jsx)(_SwiperPagIndicator.default, Object.assign({}, props.indicatorProps, {
          vertical: vertical,
          total: count,
          current: current
        }))
      }));
    }

    if (typeof props.indicator === 'function') {
      return props.indicator(count, current);
    }

    return null;
  };

  function swipeTo(index, immediate = false) {
    const roundedIndex = Math.round(index);
    const targetIndex = loop ? modulus(roundedIndex, count) : (0, _bound.bound)(roundedIndex, 0, count - 1);
    setCurrent(targetIndex);
    api.start({
      position: (loop ? roundedIndex : boundIndex(roundedIndex)) * 100,
      immediate
    });
  }

  const swipeNext = () => {
    swipeTo(Math.round(position.get() / 100) + 1);
  };

  const swipePrev = () => {
    swipeTo(Math.round(position.get() / 100) - 1);
  };

  (0, _react().useImperativeHandle)(ref, () => ({
    activeIndex: current,
    swipeTo,
    swipeNext,
    swipePrev,
    enable: () => {
      setEnabled(true);
    },
    disable: () => {
      setEnabled(false);
    }
  }));
  (0, _hooks.useIsomorphicLayoutEffect)(() => {
    const maxIndex = validChildren.length - 1;

    if (current > maxIndex) {
      swipeTo(maxIndex, true);
    }
  });
  (0, _hooks.useUpdateEffect)(() => {
    var _a;

    (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, current);
  }, [current]);
  (0, _react().useEffect)(() => {
    if (!autoplay || dragging) return _utils.noop;
    const autoplayInterval = typeof autoplay === 'boolean' ? 5000 : autoplay;
    const interval = window.setInterval(() => {
      swipeNext();
    }, autoplayInterval);
    return () => {
      window.clearInterval(interval);
    }; // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoplay, dragging]);

  const renderTrackInner = () => {
    if (loop) {
      return (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('track-inner', {
          vertical
        })),
        style: trackStyle
      }, {
        children: _react().default.Children.map(validChildren, (child, index) => {
          return (0, _jsxRuntime().jsx)(_web().animated.div, Object.assign({
            className: (0, _clsx().default)(bem('slide')),
            style: {
              [axis]: position.to(pos => {
                let finalPosition = -pos + index * 100;
                const totalWidth = count * 100;
                const flagWidth = totalWidth / 2;
                finalPosition = modulus(finalPosition + flagWidth, totalWidth) - flagWidth;
                return `${finalPosition}%`;
              }),
              [vertical ? 'top' : 'left']: `-${index * 100}%`
            }
          }, {
            children: _react().default.cloneElement(child, {
              ref: setChildrenRefs(index)
            })
          }));
        })
      }));
    }

    return (0, _jsxRuntime().jsx)(_web().animated.div, Object.assign({
      className: (0, _clsx().default)(bem('track-inner')),
      style: {
        [axis]: position.to(position => `${-position}%`)
      }
    }, {
      children: _react().default.Children.map(validChildren, (child, index) => {
        return (0, _jsxRuntime().jsx)("div", Object.assign({
          className: (0, _clsx().default)(bem('slide'))
        }, {
          children: _react().default.cloneElement(child, {
            ref: setChildrenRefs(index)
          })
        }));
      })
    }));
  };

  if (count === 0) {
    (0, _devLog.devWarning)('Swiper', '`Swiper` needs at least one child.');
  }

  return (0, _jsxRuntime().jsxs)("div", Object.assign({
    className: (0, _clsx().default)(props.className, bem({
      vertical
    })),
    style: computedStyle
  }, {
    children: [(0, _jsxRuntime().jsx)("div", Object.assign({
      ref: trackRef,
      className: (0, _clsx().default)(bem('track', {
        'allow-touch-move': props.touchable
      })),
      onClickCapture: e => {
        if (draggingRef.current) {
          e.stopPropagation();
        }
      }
    }, props.touchable ? bind() : {}, {
      children: renderTrackInner()
    })), renderIndicator()]
  }));
}); // defaultProps defined if need

Swiper.defaultProps = {
  initialSwipe: 0,
  touchable: true,
  enabled: true,
  rubberband: true,
  autoplay: false,
  slideSize: 100,
  trackOffset: 0,
  stuckAtBoundary: false,
  preventScroll: true
};
var _default = Swiper;
exports.default = _default;

function modulus(value, division) {
  const remainder = value % division;
  return remainder < 0 ? remainder + division : remainder;
}

function isScrollTarget(element, parent) {
  if (!parent) return false;

  if (element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight) {
    return true;
  }

  if (element.parentElement && element.parentElement !== parent) {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    return isScrollTarget(element.parentElement, parent);
  }

  return false;
}