import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, isVNode as _isVNode, createVNode as _createVNode } from "vue";
import "./styles/image.css";
import { computed, defineComponent, h, nextTick, onBeforeMount, ref, vShow, watch, withDirectives } from "vue";
import { IN_BROWSER, SUPPORTS_INTERSECTION_OBSERVER, convertToUnit, useRender } from "@veno-ui/utils";
import { Responsive } from "../responsive";
import { MaybeTransition, makeTransitionProps } from "../../composables/transition";
function _isSlot(s) {
  return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !_isVNode(s);
}
const Image = defineComponent({
  name: "VeImage",
  props: {
    /**
     * @zh 纵横比
     */
    aspectRatio: [String, Number],
    /**
     * @zh alt
     */
    alt: String,
    /**
     * @zh object-fit: cover
     */
    cover: Boolean,
    /**
     * @zh 立即加载
     */
    eager: Boolean,
    /**
     * @zh 渐变
     */
    gradient: String,
    /**
     * @zh 懒加载 src
     */
    lazySrc: String,
    /**
     * @zh IntersectionObserverInit
     */
    options: {
      type: Object,
      // For more information on types, navigate to:
      // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
      default: () => ({
        root: void 0,
        rootMargin: void 0,
        threshold: void 0
      })
    },
    /**
     * @zh sizes
     */
    sizes: String,
    /**
     * @zh src
     */
    src: String,
    /**
     * @zh srcset
     */
    srcset: String,
    /**
     * @zh 宽度
     */
    width: [String, Number],
    ...makeTransitionProps()
  },
  emits: {
    loadstart: (_src, _image) => true,
    load: (_src, _image) => true,
    error: (_src, _image) => true
  },
  setup(props, {
    emit,
    slots
  }) {
    const currentSrc = ref("");
    const image = ref();
    const state = ref(props.eager ? "loading" : "idle");
    const naturalWidth = ref();
    const naturalHeight = ref();
    const aspectRatio = computed(() => {
      return Number(props.aspectRatio || 0) || naturalWidth.value / naturalHeight.value || 0;
    });
    watch(() => props.src, () => {
      init(state.value !== "idle");
    });
    onBeforeMount(() => init());
    function init(isIntersecting) {
      if (props.eager && isIntersecting)
        return;
      if (SUPPORTS_INTERSECTION_OBSERVER && !isIntersecting && !props.eager)
        return;
      state.value = "loading";
      if (props.lazySrc && IN_BROWSER) {
        const lazyImg = new window.Image();
        lazyImg.src = props.lazySrc;
        pollForSize(lazyImg, null);
      }
      if (!props.src)
        return;
      nextTick(() => {
        emit("loadstart", image.value?.currentSrc || props.src, image.value);
        if (image.value?.complete) {
          if (!image.value.naturalWidth)
            onError();
          if (state.value === "error")
            return;
          if (!aspectRatio.value)
            pollForSize(image.value, null);
          onLoad();
        } else {
          if (!aspectRatio.value)
            pollForSize(image.value);
          getSrc();
        }
      });
    }
    function onLoad() {
      getSrc();
      state.value = "loaded";
      emit("load", image.value?.currentSrc || props.src, image.value);
    }
    function onError() {
      state.value = "error";
      emit("error", image.value?.currentSrc || props.src, image.value);
    }
    function getSrc() {
      const img = image.value;
      if (img)
        currentSrc.value = img.currentSrc || img.src;
    }
    function pollForSize(img, timeout = 100) {
      const poll = () => {
        const {
          naturalHeight: imgHeight,
          naturalWidth: imgWidth
        } = img;
        if (imgHeight || imgWidth) {
          naturalWidth.value = imgWidth;
          naturalHeight.value = imgHeight;
        } else if (!img.complete && state.value === "loading" && timeout != null) {
          setTimeout(poll, timeout);
        } else if (img.currentSrc.endsWith(".svg") || img.currentSrc.startsWith("data:image/svg+xml")) {
          naturalWidth.value = 1;
          naturalHeight.value = 1;
        }
      };
      poll();
    }
    const containClasses = computed(() => ({
      "ve-image__img--cover": props.cover,
      "ve-image__img--contain": !props.cover
    }));
    const __image = computed(() => {
      let _slot;
      if (!props.src || state.value === "idle")
        return;
      const img = h("img", {
        class: ["ve-image__img", containClasses.value],
        src: props.src,
        srcset: props.srcset,
        sizes: props.sizes,
        ref: image,
        onLoad,
        onError
      });
      const sources = slots.sources?.();
      return _createVNode(MaybeTransition, {
        "transition": props.transition,
        "appear": true
      }, _isSlot(_slot = withDirectives(sources ? _createVNode("picture", {
        "class": "ve-image__picture"
      }, [sources, img]) : img, [[vShow, state.value === "loaded"]])) ? _slot : {
        default: () => [_slot]
      });
    });
    const __preloadImage = computed(() => _createVNode(MaybeTransition, {
      "transition": props.transition
    }, {
      default: () => [props.lazySrc && state.value !== "loaded" && _createVNode("img", {
        "class": ["ve-image__img", "ve-image__img--preload", containClasses.value],
        "src": props.lazySrc,
        "alt": ""
      }, null)]
    }));
    const __placeholder = computed(() => {
      if (!slots.placeholder)
        return;
      return _createVNode(MaybeTransition, {
        "transition": props.transition,
        "appear": true
      }, {
        default: () => [(state.value === "loading" || state.value === "error" && !slots.error) && _createVNode("div", {
          "class": "ve-image__placeholder"
        }, [slots.placeholder()])]
      });
    });
    const __error = computed(() => {
      if (!slots.error)
        return;
      return _createVNode(MaybeTransition, {
        "transition": props.transition,
        "appear": true
      }, {
        default: () => [state.value === "error" && _createVNode("div", {
          "class": "ve-image__error"
        }, [slots.error()])]
      });
    });
    const __gradient = computed(() => {
      if (!props.gradient)
        return;
      return _createVNode("div", {
        "class": "ve-image__gradient",
        "style": {
          backgroundImage: `linear-gradient(${props.gradient})`
        }
      }, null);
    });
    const isBooted = ref(false);
    {
      const stop = watch(aspectRatio, (val) => {
        if (val) {
          requestAnimationFrame(() => {
            requestAnimationFrame(() => {
              isBooted.value = true;
            });
          });
          stop();
        }
      });
    }
    useRender(() => _withDirectives(_createVNode(Responsive, {
      "class": ["ve-image", {
        "ve-image--booting": !isBooted.value
      }],
      "style": {
        width: convertToUnit(props.width === "auto" ? naturalWidth.value : props.width)
      },
      "aspectRatio": aspectRatio.value,
      "aria-label": props.alt,
      "role": props.alt ? "img" : void 0
    }, {
      additional: () => [__image.value, __preloadImage.value, __gradient.value, __placeholder.value, __error.value],
      default: slots.default
    }), [[_resolveDirective("intersect"), {
      handler: init,
      options: props.options
    }, null, {
      once: true
    }]]));
    return {
      currentSrc,
      image,
      state,
      naturalWidth,
      naturalHeight
    };
  }
});
export {
  Image
};
//# sourceMappingURL=image.mjs.map
