"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const index$1 = require("../../../../../node_modules/@vueuse/core/index.js");
const types = require("../../../../utils/types.js");
const shared_esmBundler = require("../../../../../../@vue/shared/dist/shared.esm-bundler.js");
const scroll = require("../../../../utils/dom/scroll.js");
const index = require("../../../../hooks/use-namespace/index.js");
const useCache = require("../hooks/use-cache.js");
const defaults = require("../defaults.js");
const props = require("../props.js");
const utils = require("../utils.js");
const scrollbar = require("../components/scrollbar.js");
const useGridWheel = require("../hooks/use-grid-wheel.js");
const useGridTouch = require("../hooks/use-grid-touch.js");
const Vue = require("vue");
const index$2 = require("../../../../../node_modules/@vueuse/shared/index.js");
const createGrid = ({ name, clearCache, getColumnPosition, getColumnStartIndexForOffset, getColumnStopIndexForStartIndex, getEstimatedTotalHeight, getEstimatedTotalWidth, getColumnOffset, getRowOffset, getRowPosition, getRowStartIndexForOffset, getRowStopIndexForStartIndex, initCache, injectToInstance, validateProps }) => {
  return Vue.defineComponent({
    name: name ?? "ElVirtualList",
    props: props.virtualizedGridProps,
    emits: [defaults.ITEM_RENDER_EVT, defaults.SCROLL_EVT],
    setup(props2, { emit, expose, slots }) {
      const ns = index.useNamespace("vl");
      validateProps(props2);
      const instance = Vue.getCurrentInstance();
      const cache = Vue.ref(initCache(props2, instance));
      injectToInstance == null ? void 0 : injectToInstance(instance, cache);
      const windowRef = Vue.ref();
      const hScrollbar = Vue.ref();
      const vScrollbar = Vue.ref();
      const innerRef = Vue.ref();
      const states = Vue.ref({
        isScrolling: false,
        scrollLeft: types.isNumber(props2.initScrollLeft) ? props2.initScrollLeft : 0,
        scrollTop: types.isNumber(props2.initScrollTop) ? props2.initScrollTop : 0,
        updateRequested: false,
        xAxisScrollDir: defaults.FORWARD,
        yAxisScrollDir: defaults.FORWARD
      });
      const getItemStyleCache = useCache.useCache();
      const parsedHeight = Vue.computed(() => Number.parseInt(`${props2.height}`, 10));
      const parsedWidth = Vue.computed(() => Number.parseInt(`${props2.width}`, 10));
      const columnsToRender = Vue.computed(() => {
        const { totalColumn, totalRow, columnCache } = props2;
        const { isScrolling, xAxisScrollDir, scrollLeft } = Vue.unref(states);
        if (totalColumn === 0 || totalRow === 0) return [
          0,
          0,
          0,
          0
        ];
        const startIndex = getColumnStartIndexForOffset(props2, scrollLeft, Vue.unref(cache));
        const stopIndex = getColumnStopIndexForStartIndex(props2, startIndex, scrollLeft, Vue.unref(cache));
        const cacheBackward = !isScrolling || xAxisScrollDir === defaults.BACKWARD ? Math.max(1, columnCache) : 1;
        const cacheForward = !isScrolling || xAxisScrollDir === defaults.FORWARD ? Math.max(1, columnCache) : 1;
        return [
          Math.max(0, startIndex - cacheBackward),
          Math.max(0, Math.min(totalColumn - 1, stopIndex + cacheForward)),
          startIndex,
          stopIndex
        ];
      });
      const rowsToRender = Vue.computed(() => {
        const { totalColumn, totalRow, rowCache } = props2;
        const { isScrolling, yAxisScrollDir, scrollTop } = Vue.unref(states);
        if (totalColumn === 0 || totalRow === 0) return [
          0,
          0,
          0,
          0
        ];
        const startIndex = getRowStartIndexForOffset(props2, scrollTop, Vue.unref(cache));
        const stopIndex = getRowStopIndexForStartIndex(props2, startIndex, scrollTop, Vue.unref(cache));
        const cacheBackward = !isScrolling || yAxisScrollDir === defaults.BACKWARD ? Math.max(1, rowCache) : 1;
        const cacheForward = !isScrolling || yAxisScrollDir === defaults.FORWARD ? Math.max(1, rowCache) : 1;
        return [
          Math.max(0, startIndex - cacheBackward),
          Math.max(0, Math.min(totalRow - 1, stopIndex + cacheForward)),
          startIndex,
          stopIndex
        ];
      });
      const estimatedTotalHeight = Vue.computed(() => getEstimatedTotalHeight(props2, Vue.unref(cache)));
      const estimatedTotalWidth = Vue.computed(() => getEstimatedTotalWidth(props2, Vue.unref(cache)));
      const windowStyle = Vue.computed(() => [
        {
          position: "relative",
          overflow: "hidden",
          WebkitOverflowScrolling: "touch",
          willChange: "transform"
        },
        {
          direction: props2.direction,
          height: types.isNumber(props2.height) ? `${props2.height}px` : props2.height,
          width: types.isNumber(props2.width) ? `${props2.width}px` : props2.width
        },
        props2.style ?? {}
      ]);
      const innerStyle = Vue.computed(() => {
        const width = `${Vue.unref(estimatedTotalWidth)}px`;
        return {
          height: `${Vue.unref(estimatedTotalHeight)}px`,
          pointerEvents: Vue.unref(states).isScrolling ? "none" : void 0,
          width,
          margin: 0,
          boxSizing: "border-box"
        };
      });
      const emitEvents = () => {
        const { totalColumn, totalRow } = props2;
        if (totalColumn > 0 && totalRow > 0) {
          const [columnCacheStart, columnCacheEnd, columnVisibleStart, columnVisibleEnd] = Vue.unref(columnsToRender);
          const [rowCacheStart, rowCacheEnd, rowVisibleStart, rowVisibleEnd] = Vue.unref(rowsToRender);
          emit(defaults.ITEM_RENDER_EVT, {
            columnCacheStart,
            columnCacheEnd,
            rowCacheStart,
            rowCacheEnd,
            columnVisibleStart,
            columnVisibleEnd,
            rowVisibleStart,
            rowVisibleEnd
          });
        }
        const { scrollLeft, scrollTop, updateRequested, xAxisScrollDir, yAxisScrollDir } = Vue.unref(states);
        emit(defaults.SCROLL_EVT, {
          xAxisScrollDir,
          scrollLeft,
          yAxisScrollDir,
          scrollTop,
          updateRequested
        });
      };
      const onScroll = (e) => {
        const { clientHeight, clientWidth, scrollHeight, scrollLeft, scrollTop, scrollWidth } = e.currentTarget;
        const _states = Vue.unref(states);
        if (_states.scrollTop === scrollTop && _states.scrollLeft === scrollLeft) return;
        let _scrollLeft = scrollLeft;
        if (utils.isRTL(props2.direction)) switch (utils.getRTLOffsetType()) {
          case defaults.RTL_OFFSET_NAG:
            _scrollLeft = -scrollLeft;
            break;
          case defaults.RTL_OFFSET_POS_DESC:
            _scrollLeft = scrollWidth - clientWidth - scrollLeft;
            break;
        }
        states.value = {
          ..._states,
          isScrolling: true,
          scrollLeft: _scrollLeft,
          scrollTop: Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight)),
          updateRequested: true,
          xAxisScrollDir: utils.getScrollDir(_states.scrollLeft, _scrollLeft),
          yAxisScrollDir: utils.getScrollDir(_states.scrollTop, scrollTop)
        };
        Vue.nextTick(() => resetIsScrolling());
        onUpdated();
        emitEvents();
      };
      const onVerticalScroll = (distance, totalSteps) => {
        const height = Vue.unref(parsedHeight);
        const offset = (estimatedTotalHeight.value - height) / totalSteps * distance;
        scrollTo({ scrollTop: Math.min(estimatedTotalHeight.value - height, offset) });
      };
      const onHorizontalScroll = (distance, totalSteps) => {
        const width = Vue.unref(parsedWidth);
        const offset = (estimatedTotalWidth.value - width) / totalSteps * distance;
        scrollTo({ scrollLeft: Math.min(estimatedTotalWidth.value - width, offset) });
      };
      const { onWheel } = useGridWheel.useGridWheel({
        atXStartEdge: Vue.computed(() => states.value.scrollLeft <= 0),
        atXEndEdge: Vue.computed(() => states.value.scrollLeft >= estimatedTotalWidth.value - Vue.unref(parsedWidth)),
        atYStartEdge: Vue.computed(() => states.value.scrollTop <= 0),
        atYEndEdge: Vue.computed(() => states.value.scrollTop >= estimatedTotalHeight.value - Vue.unref(parsedHeight))
      }, (x, y) => {
        var _a, _b, _c, _d;
        (_b = (_a = hScrollbar.value) == null ? void 0 : _a.onMouseUp) == null ? void 0 : _b.call(_a);
        (_d = (_c = vScrollbar.value) == null ? void 0 : _c.onMouseUp) == null ? void 0 : _d.call(_c);
        const width = Vue.unref(parsedWidth);
        const height = Vue.unref(parsedHeight);
        scrollTo({
          scrollLeft: Math.min(states.value.scrollLeft + x, estimatedTotalWidth.value - width),
          scrollTop: Math.min(states.value.scrollTop + y, estimatedTotalHeight.value - height)
        });
      });
      index$1.useEventListener(windowRef, "wheel", onWheel, { passive: false });
      const scrollTo = ({ scrollLeft = states.value.scrollLeft, scrollTop = states.value.scrollTop }) => {
        scrollLeft = Math.max(scrollLeft, 0);
        scrollTop = Math.max(scrollTop, 0);
        const _states = Vue.unref(states);
        if (scrollTop === _states.scrollTop && scrollLeft === _states.scrollLeft) return;
        states.value = {
          ..._states,
          xAxisScrollDir: utils.getScrollDir(_states.scrollLeft, scrollLeft),
          yAxisScrollDir: utils.getScrollDir(_states.scrollTop, scrollTop),
          scrollLeft,
          scrollTop,
          updateRequested: true
        };
        Vue.nextTick(() => resetIsScrolling());
        onUpdated();
        emitEvents();
      };
      const { touchStartX, touchStartY, handleTouchStart, handleTouchMove } = useGridTouch.useGridTouch(windowRef, states, scrollTo, estimatedTotalWidth, estimatedTotalHeight, parsedWidth, parsedHeight);
      const scrollToItem = (rowIndex = 0, columnIdx = 0, alignment = defaults.AUTO_ALIGNMENT) => {
        const _states = Vue.unref(states);
        columnIdx = Math.max(0, Math.min(columnIdx, props2.totalColumn - 1));
        rowIndex = Math.max(0, Math.min(rowIndex, props2.totalRow - 1));
        const scrollBarWidth = scroll.getScrollBarWidth(ns.namespace.value);
        const _cache = Vue.unref(cache);
        const estimatedHeight = getEstimatedTotalHeight(props2, _cache);
        const estimatedWidth = getEstimatedTotalWidth(props2, _cache);
        scrollTo({
          scrollLeft: getColumnOffset(props2, columnIdx, alignment, _states.scrollLeft, _cache, estimatedWidth > props2.width ? scrollBarWidth : 0),
          scrollTop: getRowOffset(props2, rowIndex, alignment, _states.scrollTop, _cache, estimatedHeight > props2.height ? scrollBarWidth : 0)
        });
      };
      const getItemStyle = (rowIndex, columnIndex) => {
        const { columnWidth, direction, rowHeight } = props2;
        const itemStyleCache = getItemStyleCache.value(clearCache && columnWidth, clearCache && rowHeight, clearCache && direction);
        const key = `${rowIndex},${columnIndex}`;
        if (shared_esmBundler.hasOwn(itemStyleCache, key)) return itemStyleCache[key];
        else {
          const [, left] = getColumnPosition(props2, columnIndex, Vue.unref(cache));
          const _cache = Vue.unref(cache);
          const rtl = utils.isRTL(direction);
          const [height, top] = getRowPosition(props2, rowIndex, _cache);
          const [width] = getColumnPosition(props2, columnIndex, _cache);
          itemStyleCache[key] = {
            position: "absolute",
            left: rtl ? void 0 : `${left}px`,
            right: rtl ? `${left}px` : void 0,
            top: `${top}px`,
            height: `${height}px`,
            width: `${width}px`
          };
          return itemStyleCache[key];
        }
      };
      const resetIsScrolling = () => {
        states.value.isScrolling = false;
        Vue.nextTick(() => {
          getItemStyleCache.value(-1, null, null);
        });
      };
      Vue.onMounted(() => {
        if (!index$2.isClient) return;
        const { initScrollLeft, initScrollTop } = props2;
        const windowElement = Vue.unref(windowRef);
        if (windowElement) {
          if (types.isNumber(initScrollLeft)) windowElement.scrollLeft = initScrollLeft;
          if (types.isNumber(initScrollTop)) windowElement.scrollTop = initScrollTop;
        }
        emitEvents();
      });
      const onUpdated = () => {
        const { direction } = props2;
        const { scrollLeft, scrollTop, updateRequested } = Vue.unref(states);
        const windowElement = Vue.unref(windowRef);
        if (updateRequested && windowElement) {
          if (direction === defaults.RTL) switch (utils.getRTLOffsetType()) {
            case defaults.RTL_OFFSET_NAG:
              windowElement.scrollLeft = -scrollLeft;
              break;
            case defaults.RTL_OFFSET_POS_ASC:
              windowElement.scrollLeft = scrollLeft;
              break;
            default: {
              const { clientWidth, scrollWidth } = windowElement;
              windowElement.scrollLeft = scrollWidth - clientWidth - scrollLeft;
              break;
            }
          }
          else windowElement.scrollLeft = Math.max(0, scrollLeft);
          windowElement.scrollTop = Math.max(0, scrollTop);
        }
      };
      const { resetAfterColumnIndex, resetAfterRowIndex, resetAfter } = instance.proxy;
      expose({
        windowRef,
        innerRef,
        getItemStyleCache,
        touchStartX,
        touchStartY,
        handleTouchStart,
        handleTouchMove,
        scrollTo,
        scrollToItem,
        states,
        resetAfterColumnIndex,
        resetAfterRowIndex,
        resetAfter
      });
      const renderScrollbars = () => {
        const { scrollbarAlwaysOn, scrollbarStartGap, scrollbarEndGap, totalColumn, totalRow } = props2;
        const width = Vue.unref(parsedWidth);
        const height = Vue.unref(parsedHeight);
        const estimatedWidth = Vue.unref(estimatedTotalWidth);
        const estimatedHeight = Vue.unref(estimatedTotalHeight);
        const { scrollLeft, scrollTop } = Vue.unref(states);
        return {
          horizontalScrollbar: Vue.h(scrollbar.default, {
            ref: hScrollbar,
            alwaysOn: scrollbarAlwaysOn,
            startGap: scrollbarStartGap,
            endGap: scrollbarEndGap,
            class: ns.e("horizontal"),
            clientSize: width,
            layout: "horizontal",
            onScroll: onHorizontalScroll,
            ratio: width * 100 / estimatedWidth,
            scrollFrom: scrollLeft / (estimatedWidth - width),
            total: totalRow,
            visible: true
          }),
          verticalScrollbar: Vue.h(scrollbar.default, {
            ref: vScrollbar,
            alwaysOn: scrollbarAlwaysOn,
            startGap: scrollbarStartGap,
            endGap: scrollbarEndGap,
            class: ns.e("vertical"),
            clientSize: height,
            layout: "vertical",
            onScroll: onVerticalScroll,
            ratio: height * 100 / estimatedHeight,
            scrollFrom: scrollTop / (estimatedHeight - height),
            total: totalColumn,
            visible: true
          })
        };
      };
      const renderItems = () => {
        var _a;
        const [columnStart, columnEnd] = Vue.unref(columnsToRender);
        const [rowStart, rowEnd] = Vue.unref(rowsToRender);
        const { data, totalColumn, totalRow, useIsScrolling, itemKey } = props2;
        const children = [];
        if (totalRow > 0 && totalColumn > 0) for (let row = rowStart; row <= rowEnd; row++) for (let column = columnStart; column <= columnEnd; column++) {
          const key = itemKey({
            columnIndex: column,
            data,
            rowIndex: row
          });
          children.push(Vue.h(Vue.Fragment, { key }, (_a = slots.default) == null ? void 0 : _a.call(slots, {
            columnIndex: column,
            data,
            isScrolling: useIsScrolling ? Vue.unref(states).isScrolling : void 0,
            style: getItemStyle(row, column),
            rowIndex: row
          })));
        }
        return children;
      };
      const renderInner = () => {
        const Inner = Vue.resolveDynamicComponent(props2.innerElement);
        const children = renderItems();
        return [Vue.h(Inner, Vue.mergeProps(props2.innerProps, {
          style: Vue.unref(innerStyle),
          ref: innerRef
        }), !shared_esmBundler.isString(Inner) ? { default: () => children } : children)];
      };
      const renderWindow = () => {
        const Container = Vue.resolveDynamicComponent(props2.containerElement);
        const { horizontalScrollbar, verticalScrollbar } = renderScrollbars();
        const Inner = renderInner();
        return Vue.h("div", {
          key: 0,
          class: ns.e("wrapper"),
          role: props2.role
        }, [
          Vue.h(Container, {
            class: props2.className,
            style: Vue.unref(windowStyle),
            onScroll,
            ref: windowRef
          }, !shared_esmBundler.isString(Container) ? { default: () => Inner } : Inner),
          horizontalScrollbar,
          verticalScrollbar
        ]);
      };
      return renderWindow;
    }
  });
};
exports.default = createGrid;
