/**
 * tdesign v0.39.1-alpha.1
 * (c) 2022 tdesign
 * @license MIT
 */

'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var VueCompositionAPI = require('@vue/composition-api');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); 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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

var useVirtualScroll = function useVirtualScroll(_ref) {
  var data = _ref.data,
      container = _ref.container,
      _ref$fixedHeight = _ref.fixedHeight,
      fixedHeight = _ref$fixedHeight === void 0 ? false : _ref$fixedHeight,
      _ref$lineHeight = _ref.lineHeight,
      lineHeight = _ref$lineHeight === void 0 ? 30 : _ref$lineHeight,
      _ref$bufferSize = _ref.bufferSize,
      bufferSize = _ref$bufferSize === void 0 ? 20 : _ref$bufferSize,
      _ref$threshold = _ref.threshold,
      threshold = _ref$threshold === void 0 ? 100 : _ref$threshold;
  var state = VueCompositionAPI.reactive({
    visibleData: [],
    cachedHeight: [],
    cachedScrollY: []
  });
  var isVirtual = VueCompositionAPI.computed(function () {
    return data.value.length > threshold;
  });
  var updateId = VueCompositionAPI.ref(0);
  var trs = /* @__PURE__ */new Map();
  var visibleCount = 0;
  var beforeScrollTop = 0;
  var index = 0;
  var offset = 0;
  var start = 0;
  var last = 0;

  var reset = function reset() {
    data.value.forEach(function (item, i) {
      item.$index = i;

      if (fixedHeight) {
        state.cachedScrollY[i] = i * lineHeight;
      }
    });

    if (!fixedHeight) {
      state.cachedScrollY[data.value.length - 1] = void 0;
    }
  };

  reset();
  var scrollHeight = VueCompositionAPI.computed(function () {
    var cachedHeight = state.cachedHeight;
    var length = cachedHeight.length;

    if (length) {
      var maxScrollY = cachedHeight.reduce(function (sum, v) {
        return sum + v || lineHeight;
      }, 0);

      if (cachedHeight.length === data.value.length) {
        return maxScrollY;
      }

      var average = maxScrollY / cachedHeight.length;
      return maxScrollY + (data.value.length - cachedHeight.length) * average;
    }

    return isVirtual.value ? data.value.length * lineHeight : 0;
  });
  var translateY = VueCompositionAPI.computed(function () {
    var visibleData = state.visibleData;
    var firstRow = visibleData[0];

    if (firstRow) {
      return visibleData.length === 1 ? 0 : state.cachedScrollY[firstRow.$index];
    }

    return 0;
  });

  var updateVisibleData = function updateVisibleData() {
    last = Math.min(start + visibleCount + bufferSize * 2, data.value.length);
    state.visibleData = data.value.slice(start, last);
  };

  var calculateScrollY = function calculateScrollY() {
    var _anchorDom$getBoundin;

    var anchorDom = trs.get(index);

    if (!anchorDom) {
      return;
    }

    var anchorDomHeight = anchorDom === null || anchorDom === void 0 ? void 0 : (_anchorDom$getBoundin = anchorDom.getBoundingClientRect()) === null || _anchorDom$getBoundin === void 0 ? void 0 : _anchorDom$getBoundin.height;
    state.cachedScrollY[index] = container.value.scrollTop - offset;
    state.cachedHeight[index] = anchorDomHeight;

    for (var i = index + 1; i <= state.visibleData[state.visibleData.length - 1].$index; i++) {
      var tr = trs.get(i);

      var _ref2 = (tr === null || tr === void 0 ? void 0 : tr.getBoundingClientRect()) || {},
          height = _ref2.height;

      state.cachedHeight[i] = height;
      var scrollY = state.cachedScrollY[i - 1] + state.cachedHeight[i - 1];
      state.cachedScrollY.splice(i, 1, scrollY);
    }

    for (var _i = index - 1; _i >= state.visibleData[0].$index; _i--) {
      var _tr = trs.get(_i);

      var _ref3 = (_tr === null || _tr === void 0 ? void 0 : _tr.getBoundingClientRect()) || {},
          _height = _ref3.height;

      state.cachedHeight[_i] = _height;

      var _scrollY = state.cachedScrollY[_i + 1] - state.cachedHeight[_i];

      state.cachedScrollY.splice(_i, 1, _scrollY);
    }

    if (state.cachedScrollY[0] > 0) {
      var distance = state.cachedScrollY[0];
      var length = Math.min(last, data.value.length);

      for (var _i2 = 0; _i2 < length; _i2++) {
        state.cachedScrollY.splice(_i2, 1, state.cachedScrollY[_i2] - distance);
      }

      var scrollTop = state.cachedScrollY[index - 1] ? state.cachedScrollY[index - 1] + offset : offset;
      container.value.scrollTop = scrollTop;
      beforeScrollTop = scrollTop;
    }

    if (state.cachedScrollY[start] < 0) {
      var s = state.cachedHeight.slice(0, Math.max(0, index)).reduce(function (sum, v) {
        return sum + v;
      }, 0) + offset;
      container.value.scrollTop = s;
      beforeScrollTop = s;

      if (s === 0) {
        index = 0;
        offset = 0;
      }
    }

    VueCompositionAPI.nextTick(function () {
      var _container$value = container.value,
          scrollTop = _container$value.scrollTop,
          scrollHeight2 = _container$value.scrollHeight,
          clientHeight = _container$value.clientHeight;

      if (scrollTop + clientHeight === scrollHeight2) {
        for (var _i3 = last - 1; _i3 >= start; _i3--) {
          if (_i3 === last - 1) {
            state.cachedScrollY.splice(_i3, 1, scrollHeight2.value - state.cachedHeight[_i3]);
          } else {
            state.cachedScrollY.splice(_i3, 1, state.cachedScrollY[_i3 + 1] - state.cachedHeight[_i3]);
          }
        }
      }
    });
  };

  var handleScroll = function handleScroll() {
    if (!isVirtual.value) return;
    var scrollTop = container.value.scrollTop;
    var distance = scrollTop - beforeScrollTop;
    beforeScrollTop = scrollTop;
    distance += offset;
    var lastIndex = index;
    if (!distance) return;

    if (distance >= 0) {
      while (lastIndex < data.value.length && distance > (state.cachedHeight[lastIndex] || lineHeight)) {
        if (!state.cachedHeight[lastIndex]) {
          state.cachedHeight[lastIndex] = lineHeight;
        }

        distance -= state.cachedHeight[lastIndex];
        lastIndex++;
      }

      if (lastIndex >= data.value.length) {
        index = data.value.length - 1;
        offset = 0;
      } else {
        index = lastIndex;
        offset = distance;
      }

      var _container$value2 = container.value,
          clientHeight = _container$value2.clientHeight,
          scrollHeight2 = _container$value2.scrollHeight;

      if (scrollTop + clientHeight === scrollHeight2) {
        index = data.value.length - visibleCount + 1;
      }

      if (start <= index - bufferSize) {
        start = Math.min(data.value.length - visibleCount, index - bufferSize);

        if (start < 0) {
          start = 0;
        }
      }
    } else {
      while (distance < 0) {
        lastIndex--;

        if (!state.cachedHeight[lastIndex]) {
          state.cachedHeight[lastIndex] = lineHeight;
        }

        distance += state.cachedHeight[lastIndex];
      }

      if (lastIndex < 0) {
        index = 0;
        offset = 0;
      } else {
        index = lastIndex;
        offset = distance;
      }

      calculateScrollY();

      if (start > index - bufferSize) {
        start = Math.max(0, index - bufferSize);
      }
    }

    updateVisibleData();
  };

  !fixedHeight && VueCompositionAPI.watch(updateId, calculateScrollY, {
    flush: "post"
  });

  var handleRowMounted = function handleRowMounted() {
    if (!isVirtual.value) return;
    updateId.value++;
  };

  VueCompositionAPI.watch(data, function () {
    reset();
    state.visibleData = [];
    state.cachedScrollY = [];
    state.cachedHeight = [];
    beforeScrollTop = 0;
    index = 0;
    offset = 0;
    start = 0;
    trs.clear();

    if (data.value.length <= threshold) {
      state.visibleData = data.value;
    } else {
      updateVisibleData();
    }

    container.value && (container.value.scrollTop = 0);
  });
  var mounted = false;

  var refreshContainer = function refreshContainer() {
    if (mounted) {
      visibleCount = Math.ceil(container.value.offsetHeight / lineHeight);
      updateVisibleData();
    }
  };

  VueCompositionAPI.onMounted(function () {
    if (!window || !window.IntersectionObserver) {
      return;
    }

    var ob = new window.IntersectionObserver(function (entries) {
      var entry = entries[0];

      if (entry.isIntersecting || entry.intersectionRatio) {
        mounted = true;
        isVirtual.value && refreshContainer();
        ob.unobserve(container.value);
      }
    });
    container.value && ob.observe(container.value);
  });
  return _objectSpread(_objectSpread({
    trs: trs,
    scrollHeight: scrollHeight
  }, VueCompositionAPI.toRefs(state)), {}, {
    translateY: translateY,
    handleScroll: handleScroll,
    handleRowMounted: handleRowMounted,
    refreshContainer: refreshContainer,
    fixedHeight: fixedHeight,
    calculateScrollY: calculateScrollY
  });
};

exports["default"] = useVirtualScroll;
//# sourceMappingURL=useVirtualScroll.js.map
