@opensig/opendesign
Version:
244 lines (243 loc) • 9 kB
JavaScript
import { defineComponent, ref, computed, watchEffect, onMounted, createBlock, openBlock, unref, normalizeStyle, normalizeClass, withCtx, createElementBlock, createCommentVNode, renderSlot, createVNode, createElementVNode } from "vue";
import { defaultPrestColorPool } from "../_utils/global.mjs";
import HtmlTag from "../_components/html-tag.mjs";
import { OLayer } from "../layer/index.mjs";
import { IconImageError, IconVideoPlay } from "../_utils/icons.mjs";
import { isObject } from "../_utils/is.mjs";
import { useIntersectionObserver } from "../hooks/use-intersection-observer.mjs";
import { requestImage } from "../_utils/helper.mjs";
import "../hooks/use-theme.mjs";
import { useScreen } from "../hooks/use-screen.mjs";
import "@vueuse/core";
import { figureProps } from "./types.mjs";
const _hoisted_1 = {
key: 0,
class: "o-figure-wrap"
};
const _hoisted_2 = {
key: 0,
class: "o-figure-error-wrap"
};
const _hoisted_3 = ["src", "alt", "loading"];
const _hoisted_4 = ["src", "alt", "loading"];
const _hoisted_5 = {
key: 2,
class: "o-figure-main"
};
const _hoisted_6 = {
key: 0,
class: "o-figure-mask"
};
const _hoisted_7 = { class: "o-figure-play-icon" };
const _hoisted_8 = {
key: 1,
class: "o-figure-content"
};
const _hoisted_9 = { class: "o-figure-title" };
const _hoisted_10 = { class: "o-figure-preview-img" };
const _hoisted_11 = ["src"];
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "OFigure",
props: figureProps,
emits: ["error", "load", "preview"],
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emits = __emit;
const imgRef = ref(null);
const { isPhonePad } = useScreen();
const isLoading = ref(true);
const isError = ref(false);
const prestColor = props.colorful ? defaultPrestColorPool.value.pick() : "";
const imgSrc = ref(void 0);
const bgUrl = computed(() => props.background && imgSrc.value ? `url(${imgSrc.value})` : void 0);
const useObserver = props.lazy && props.background || isObject(props.lazy);
const onImgLoaded = () => {
isLoading.value = false;
isError.value = false;
emits("load");
};
const onImgError = () => {
isLoading.value = false;
isError.value = true;
emits("error");
};
watchEffect(() => {
if (!props.src) {
return;
}
if (props.lazy === false) {
imgSrc.value = props.src;
} else {
if (!useObserver) {
imgSrc.value = props.src;
}
}
if (props.background && imgSrc.value) {
requestImage(imgSrc.value).then(onImgLoaded).catch(onImgError);
}
});
let io = null;
const rootEl = ref(null);
onMounted(() => {
if (imgRef.value && imgRef.value.complete && imgSrc.value) {
onImgLoaded();
}
if (useObserver) {
io = useIntersectionObserver(isObject(props.lazy) ? props.lazy : {});
if (rootEl.value) {
io == null ? void 0 : io.observe(rootEl.value.$el, (entry) => {
if (entry.isIntersecting) {
imgSrc.value = props.src;
}
});
}
}
});
const paddingTop = computed(() => {
if (props.ratio) {
return `${(1 / props.ratio * 100).toFixed(2)}%`;
}
return "";
});
const previewVisible = ref(false);
const canPreview = computed(() => props.preview || props.lazyPreview);
const previewCloseTypes = computed(() => {
if (!props.previewClose) {
return isPhonePad.value ? ["body", "mask", "button"] : ["mask", "button"];
} else if (Array.isArray(props.previewClose)) {
return props.previewClose;
}
return [props.previewClose];
});
const isMaskClose = computed(() => previewCloseTypes.value.includes("mask"));
const isButtonClose = computed(() => previewCloseTypes.value.includes("button"));
const isBodyClose = computed(() => previewCloseTypes.value.includes("body"));
const preview = (visible = true) => {
if (canPreview.value) {
previewVisible.value = visible;
}
};
const onPreviewChange = (visible) => {
emits("preview", visible);
};
const onPreviewImgClick = () => {
if (isBodyClose.value) {
previewVisible.value = false;
}
};
const onFigureClick = () => {
if (props.preview) {
preview();
}
};
__expose({
/**
* @zh-CN 预览图片
* @en-US Preview the image
*/
preview
});
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(HtmlTag), {
ref_key: "rootEl",
ref: rootEl,
tag: !!props.href ? "a" : "div",
class: normalizeClass(["o-figure", {
"is-loading": isLoading.value,
"is-error": isError.value,
"is-colorful": props.colorful,
"o-figure-hoverable": props.hoverable || !!props.href || props.preview || props.videoPoster,
"o-figure-previewable": props.preview,
"o-figure-video-poster": props.videoPoster,
"o-figure-bg": props.background,
"o-figure-no-ratio": !props.ratio
}]),
href: props.href,
style: normalizeStyle({
"--figure-prest-color": unref(prestColor),
"--figure-padding-top": paddingTop.value,
"--figure-fit": props.fit,
backgroundImage: bgUrl.value
}),
onClick: onFigureClick
}, {
default: withCtx(() => [
paddingTop.value || isError.value ? (openBlock(), createElementBlock("div", _hoisted_1, [
isError.value ? (openBlock(), createElementBlock("div", _hoisted_2, [
renderSlot(_ctx.$slots, "error", {}, () => [
createVNode(unref(IconImageError))
])
])) : !props.background && imgSrc.value ? (openBlock(), createElementBlock("img", {
key: 1,
ref_key: "imgRef",
ref: imgRef,
src: imgSrc.value,
alt: props.alt,
class: "o-figure-img-ratio",
loading: props.lazy === true ? "lazy" : "eager",
onLoad: onImgLoaded,
onError: onImgError
}, null, 40, _hoisted_3)) : createCommentVNode("v-if", true)
])) : imgSrc.value && !props.background ? (openBlock(), createElementBlock("img", {
key: 1,
ref_key: "imgRef",
ref: imgRef,
src: imgSrc.value,
alt: props.alt,
class: "o-figure-img",
loading: props.lazy === true ? "lazy" : "eager",
onLoad: onImgLoaded,
onError: onImgError
}, null, 40, _hoisted_4)) : createCommentVNode("v-if", true),
props.videoPoster || _ctx.$slots.content || _ctx.$slots.title || _ctx.$slots.default ? (openBlock(), createElementBlock("div", _hoisted_5, [
renderSlot(_ctx.$slots, "default"),
props.videoPoster ? (openBlock(), createElementBlock("div", _hoisted_6, [
renderSlot(_ctx.$slots, "play-icon", {}, () => [
createElementVNode("div", _hoisted_7, [
createVNode(unref(IconVideoPlay))
])
])
])) : createCommentVNode("v-if", true),
_ctx.$slots.content || _ctx.$slots.title ? (openBlock(), createElementBlock("div", _hoisted_8, [
renderSlot(_ctx.$slots, "content", {}, () => [
createElementVNode("div", _hoisted_9, [
renderSlot(_ctx.$slots, "title")
])
])
])) : createCommentVNode("v-if", true)
])) : createCommentVNode("v-if", true),
canPreview.value ? (openBlock(), createBlock(unref(OLayer), {
key: 3,
visible: previewVisible.value,
"onUpdate:visible": _cache[0] || (_cache[0] = ($event) => previewVisible.value = $event),
class: "o-figure-preview-layer",
"mask-close": isMaskClose.value,
"button-close": isButtonClose.value,
onChange: onPreviewChange
}, {
default: withCtx(() => [
createElementVNode("div", {
class: "o-figure-preview-wrapper",
onClick: onPreviewImgClick
}, [
renderSlot(_ctx.$slots, "preview", { image: imgSrc.value }, () => [
createElementVNode("div", _hoisted_10, [
createElementVNode("img", { src: imgSrc.value }, null, 8, _hoisted_11)
]),
renderSlot(_ctx.$slots, "preview-extra")
])
])
]),
_: 3
/* FORWARDED */
}, 8, ["visible", "mask-close", "button-close"])) : createCommentVNode("v-if", true)
]),
_: 3
/* FORWARDED */
}, 8, ["tag", "href", "class", "style"]);
};
}
});
export {
_sfc_main as default
};