/**
 * ldesign v0.2.14
 * (c) 2022/11/2 16:16 built by swimly
 * @license MIT
 */

import Vue from 'vue';
import { off, getScrollContainer, on, getScroll, scrollTo } from '../../utils/dom.js';
import { renderLNodeJSX } from '../../utils/render-node.js';
import { getClassPrefixMixins } from '../config-provider/config-receiver.js';
import mixins from '../../utils/mixins.js';
import { Affix } from '../affix/index.js';
import { ANCHOR_SHARP_REGEXP, getOffsetTop } from './utils.js';
import { AnchorProps } from './props.js';
import 'raf';
import 'lodash/isString';
import '../../_chunks/dep-70c789e5.js';
import '../../_chunks/dep-5210251b.js';
import '../../utils/easing.js';
import 'lodash';
import 'lodash/mergeWith';
import '../config-provider/context.js';
import '../../_chunks/dep-def4c2ce.js';
import '../../utils/with-install.js';
import '../../config.js';
import '../affix/affix.js';
import 'lodash/isFunction';
import '../affix/props.js';

const classPrefixMixins = getClassPrefixMixins("anchor");
var _Anchor = mixins(Vue, classPrefixMixins).extend({
  name: "LAnchor",
  components: {
    LAffix: Affix
  },
  props: {
    ...AnchorProps
  },
  provide() {
    return {
      tAnchor: this
    };
  },
  data() {
    return {
      links: [],
      active: "",
      activeLineStyle: false
    };
  },
  watch: {
    attach() {
      if (this.scrollContainer) off(this.scrollContainer, "scroll", this.handleScroll);
      this.getScrollContainer();
    },
    size: {
      async handler() {
        await Vue.nextTick();
        this.updateActiveLine();
      },
      immediate: true
    }
  },
  methods: {
    getScrollContainer() {
      const {
        container
      } = this;
      this.scrollContainer = getScrollContainer(container);
      on(this.scrollContainer, "scroll", this.handleScroll);
      this.handleScroll();
    },
    getAnchorTarget(link) {
      const matcher = link.match(ANCHOR_SHARP_REGEXP);
      if (!matcher) return;
      const anchor = document.getElementById(matcher[1]);
      if (!anchor) return;
      return anchor;
    },
    registerLink(link) {
      const {
        links
      } = this;
      if (!ANCHOR_SHARP_REGEXP.test(link) || links.includes(link)) return;
      links.push(link);
    },
    unregisterLink(link) {
      this.links = this.links.filter(each => each !== link);
    },
    async setCurrentActiveLink(link) {
      const {
        active
      } = this;
      if (active === link) return;
      this.active = link;
      this.emitChange(link, active);
      await Vue.nextTick();
      this.updateActiveLine();
    },
    updateActiveLine() {
      const ele = this.$el.querySelector(`.${this.commonStatusClassName.active}>a`);
      if (!ele) {
        this.activeLineStyle = false;
        return;
      }
      const {
        offsetTop: top,
        offsetHeight: height
      } = ele;
      this.activeLineStyle = {
        top: `${top}px`,
        height: `${height}px`,
        opacity: 1
      };
    },
    emitChange(currentLink, prevLink) {
      this.$emit("change", currentLink, prevLink);
      if (this.onChange) this.onChange(currentLink, prevLink);
    },
    handleLinkClick(link) {
      this.$emit("click", link);
      if (this.onClick) this.onClick(link);
    },
    async handleScrollTo(link) {
      const anchor = this.getAnchorTarget(link);
      this.setCurrentActiveLink(link);
      if (!anchor) return;
      this.handleScrollLock = true;
      const {
        scrollContainer,
        targetOffset
      } = this;
      const scrollTop = getScroll(scrollContainer);
      const offsetTop = getOffsetTop(anchor, scrollContainer);
      const top = scrollTop + offsetTop - targetOffset;
      await scrollTo(top, {
        container: scrollContainer
      });
      this.handleScrollLock = false;
    },
    handleScroll() {
      if (this.handleScrollLock) return;
      const {
        links,
        bounds,
        targetOffset
      } = this;
      const filters = [];
      let active = "";
      links.forEach(link => {
        const anchor = this.getAnchorTarget(link);
        if (!anchor) return;
        const top = getOffsetTop(anchor, this.scrollContainer);
        if (top < bounds + targetOffset) {
          filters.push({
            link,
            top
          });
        }
      });
      if (filters.length) {
        const latest = filters.reduce((prev, cur) => prev.top > cur.top ? prev : cur);
        active = latest.link;
      }
      this.setCurrentActiveLink(active);
    },
    renderCursor() {
      const h = this.$createElement;
      const titleContent = renderLNodeJSX(this, "cursor");
      return titleContent || h("div", {
        "class": `${this.componentName}__line-cursor`
      });
    }
  },
  async mounted() {
    const {
      active
    } = this;
    this.getScrollContainer();
    if (active) {
      await Vue.nextTick();
      this.handleScrollTo(active);
    }
  },
  destroyed() {
    if (!this.scrollContainer) return;
    off(this.scrollContainer, "scroll", this.handleScroll);
  },
  render() {
    const h = arguments[0];
    const {
      $scopedSlots: {
        default: children
      },
      size,
      affixProps,
      activeLineStyle
    } = this;
    const className = [this.componentName, this.commonSizeClassName[size]];
    const content = h("div", {
      "class": className
    }, [h("div", {
      "class": `${this.componentName}__line`
    }, [h("div", {
      "class": `${this.componentName}__line-cursor-wrapper`,
      "style": activeLineStyle
    }, [this.renderCursor()])]), children && children(null)]);
    if (affixProps) return h("l-affix", {
      "props": {
        ...affixProps
      }
    }, [content]);
    return content;
  }
});

export { _Anchor as default };
//# sourceMappingURL=anchor.js.map
