<template>
  <view :class="indexesClass" :style="indexesStyle">
    <scroll-view
      :class="bem.e('scroll-view')"
      :id="scrollViewId"
      scroll-y
      :scroll-top="scrollTop"
      @scroll="onScroll"
    >
      <slot></slot>
    </scroll-view>
    <sar-indexes-nav
      :anchors="anchorNames"
      :current="innerCurrent"
      @select="onNavSelect"
    />
  </view>
</template>

<script lang="ts">
import { defineComponent as _defineComponent } from "vue";
import {
  computed,
  onMounted,
  getCurrentInstance,
  ref,
  provide,
  watch,
  nextTick
} from "vue";
import {
  classNames,
  stringifyStyle,
  createBem,
  uniqid,
  getBoundingClientRect,
  matchScrollVisible,
  isNullish
} from "../utils";
import {
  indexesContextSymbol,
  indexesProps
} from "./common";
import { useSetTimeout } from "../use";
import SarIndexesNav from "../indexes-nav/indexes-nav.vue";
const __default__ = {
  options: {
    virtualHost: true,
    styleIsolation: "shared"
  }
};
export default /* @__PURE__ */ _defineComponent({
  ...__default__,
  __name: "indexes",
  props: indexesProps,
  emits: ["change"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const bem = createBem("indexes");
    const innerCurrent = ref(props.current);
    watch(
      () => props.current,
      () => {
        if (!isNullish(props.current) && anchorNames.value.includes(props.current)) {
          innerCurrent.value = props.current;
          scrollTo(props.current);
        }
      }
    );
    const instance = getCurrentInstance();
    const scrollViewId = uniqid();
    const scrollViewRect = ref();
    const scrollTop = ref(0);
    const memoScrollTop = ref(0);
    let lockScroll = false;
    const [unLockScrollLater] = useSetTimeout(() => {
      lockScroll = false;
    });
    const scrollTo = (name) => {
      if (!scrollViewRect.value) {
        return;
      }
      lockScroll = true;
      unLockScrollLater(150);
      const item = anchorRectList.value.find((item2) => item2[0] === name);
      if (item) {
        const offset = item[1].top - scrollViewRect.value.top;
        scrollTop.value = void 0;
        nextTick(() => {
          scrollTop.value = offset;
        });
      }
    };
    __expose({
      scrollTo
    });
    const onScroll = (event) => {
      memoScrollTop.value = event.detail.scrollTop;
      if (lockScroll || !scrollViewRect.value) {
        return;
      }
      matchScrollVisible(
        anchorRectList.value.map((item) => item[1]),
        (index) => {
          const name = anchorRectList.value[index][0];
          if (name !== innerCurrent.value) {
            innerCurrent.value = name;
            emit("change", name);
          }
        },
        {
          offset: scrollViewRect.value.top + memoScrollTop.value
        }
      );
    };
    onMounted(() => {
      getBoundingClientRect(`#${scrollViewId}`, instance).then((rect) => {
        scrollViewRect.value = rect;
      });
    });
    const anchorRectList = ref([]);
    const anchorMap = ref({});
    provide(indexesContextSymbol, {
      register(name, expose) {
        anchorMap.value[name] = expose;
      },
      unregister(name) {
        delete anchorMap.value[name];
      }
    });
    const getAllAnchorRect = async () => {
      const allRect = await Promise.all(
        Object.keys(anchorMap.value).map((name) => {
          const { getRect } = anchorMap.value[name];
          return new Promise((resolve) => {
            getRect().then((rect) => {
              resolve([name, rect]);
            });
          });
        })
      );
      const sortedAllRect = allRect.sort((a, b) => {
        return a[1].top - b[1].top;
      });
      return sortedAllRect;
    };
    onMounted(() => {
      nextTick(() => {
        getAllAnchorRect().then((rect) => {
          anchorRectList.value = rect;
          if (!isNullish(props.current)) {
            scrollTo(props.current);
          }
        });
      });
    });
    const anchorNames = computed(() => {
      return anchorRectList.value.map((item) => item[0]);
    });
    const onNavSelect = (name) => {
      innerCurrent.value = name;
      scrollTo(name);
      emit("change", name);
    };
    const indexesClass = computed(() => {
      return classNames(bem.b(), props.rootClass);
    });
    const indexesStyle = computed(() => {
      return stringifyStyle(props.rootStyle);
    });
    const __returned__ = { props, emit, bem, innerCurrent, instance, scrollViewId, scrollViewRect, scrollTop, memoScrollTop, get lockScroll() {
      return lockScroll;
    }, set lockScroll(v) {
      lockScroll = v;
    }, unLockScrollLater, scrollTo, onScroll, anchorRectList, anchorMap, getAllAnchorRect, anchorNames, onNavSelect, indexesClass, indexesStyle, SarIndexesNav };
    return __returned__;
  }
});
</script>

<style lang="scss">
@use './index.scss';
</style>