feat: initial commit - Phase 1 & 2 core features

This commit is contained in:
hiderfong
2026-04-22 17:07:33 +08:00
commit 1773bda06b
25005 changed files with 6252106 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import { SFCWithInstall } from "../../utils/vue/typescript.js";
import "../../utils/index.js";
import { ImageCrossorigin, ImageEmits, ImageFitType, ImageInstance, ImageProps, ImagePropsPublic, imageEmits, imageProps } from "./src/image.js";
import { _default } from "./src/image.vue.js";
//#region ../../packages/components/image/index.d.ts
declare const ElImage: SFCWithInstall<typeof _default>;
//#endregion
export { ElImage, ElImage as default, ImageCrossorigin, ImageEmits, ImageFitType, ImageInstance, ImageProps, ImagePropsPublic, imageEmits, imageProps };
+14
View File
@@ -0,0 +1,14 @@
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const require_install = require('../../utils/vue/install.js');
const require_image = require('./src/image.js');
const require_image$1 = require('./src/image2.js');
//#region ../../packages/components/image/index.ts
const ElImage = require_install.withInstall(require_image$1.default);
//#endregion
exports.ElImage = ElImage;
exports.default = ElImage;
exports.imageEmits = require_image.imageEmits;
exports.imageProps = require_image.imageProps;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["withInstall","Image"],"sources":["../../../../../packages/components/image/index.ts"],"sourcesContent":["import { withInstall } from '@element-plus/utils'\nimport Image from './src/image.vue'\n\nimport type { SFCWithInstall } from '@element-plus/utils'\n\nexport const ElImage: SFCWithInstall<typeof Image> = withInstall(Image)\nexport default ElImage\n\nexport * from './src/image'\n"],"mappings":";;;;;;AAKA,MAAa,UAAwCA,4BAAYC,wBAAM"}
+141
View File
@@ -0,0 +1,141 @@
import { EpPropFinalized, EpPropMergeType } from "../../../utils/vue/props/types.js";
import "../../../utils/index.js";
import { _default } from "./image.vue.js";
import * as vue from "vue";
import { ExtractPublicPropTypes } from "vue";
//#region ../../packages/components/image/src/image.d.ts
type ImageFitType = '' | 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
type ImageCrossorigin = 'anonymous' | 'use-credentials' | '';
interface ImageProps {
/**
* @description when enabling preview, use this flag to control whether clicking on backdrop can exit preview mode.
*/
hideOnClickModal?: boolean;
/**
* @description image source, same as native.
*/
src?: string;
/**
* @description indicate how the image should be resized to fit its container, same as [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit).
*/
fit?: ImageFitType;
/**
* @description Indicates how the browser should load the image, same as [native](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading)
*/
loading?: 'eager' | 'lazy';
/**
* @description whether to use lazy load.
*/
lazy?: boolean;
/**
* @description the container to add scroll listener when using lazy load.
*/
scrollContainer?: string | HTMLElement;
/**
* @description allow big image preview.
*/
previewSrcList?: string[];
/**
* @description whether to append image-viewer to body. A nested parent element attribute transform should have this attribute set to `true`.
*/
previewTeleported?: boolean;
/**
* @description set image preview z-index.
*/
zIndex?: number;
/**
* @description initial preview image index, less than the length of `url-list`.
*/
initialIndex?: number;
/**
* @description whether the viewer preview is infinite.
*/
infinite?: boolean;
/**
* @description whether the image-viewer can be closed by pressing ESC.
*/
closeOnPressEscape?: boolean;
/**
* @description the zoom rate of the image viewer zoom event
*/
zoomRate?: number;
/**
* @description preview image scale.
*/
scale?: number;
/**
* @description the min scale of the image viewer zoom event.
*/
minScale?: number;
/**
* @description the max scale of the image viewer zoom event.
*/
maxScale?: number;
/**
* @description show preview image progress content.
*/
showProgress?: boolean;
/**
* @description set HTML attribute: crossorigin.
*/
crossorigin?: ImageCrossorigin;
}
/**
* @deprecated Removed after 3.0.0, Use `ImageProps` instead.
*/
declare const imageProps: {
readonly hideOnClickModal: BooleanConstructor;
readonly src: EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
readonly fit: EpPropFinalized<StringConstructor, "" | "fill" | "none" | "contain" | "cover" | "scale-down", unknown, "", boolean>;
readonly loading: {
readonly type: vue.PropType<EpPropMergeType<StringConstructor, "lazy" | "eager", unknown>>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly lazy: BooleanConstructor;
readonly scrollContainer: {
readonly type: vue.PropType<EpPropMergeType<(new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement | undefined) | (((new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement | undefined)) | null)[], unknown, unknown>>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly previewSrcList: EpPropFinalized<(new (...args: any[]) => string[]) | (() => string[]) | (((new (...args: any[]) => string[]) | (() => string[])) | null)[], unknown, unknown, () => [], boolean>;
readonly previewTeleported: BooleanConstructor;
readonly zIndex: {
readonly type: vue.PropType<number>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
readonly initialIndex: EpPropFinalized<NumberConstructor, unknown, unknown, 0, boolean>;
readonly infinite: EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
readonly closeOnPressEscape: EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
readonly zoomRate: EpPropFinalized<NumberConstructor, unknown, unknown, 1.2, boolean>;
readonly scale: EpPropFinalized<NumberConstructor, unknown, unknown, 1, boolean>;
readonly minScale: EpPropFinalized<NumberConstructor, unknown, unknown, 0.2, boolean>;
readonly maxScale: EpPropFinalized<NumberConstructor, unknown, unknown, 7, boolean>;
readonly showProgress: BooleanConstructor;
readonly crossorigin: {
readonly type: vue.PropType<EpPropMergeType<(new (...args: any[]) => "" | "anonymous" | "use-credentials") | (() => ImageCrossorigin) | (((new (...args: any[]) => "" | "anonymous" | "use-credentials") | (() => ImageCrossorigin)) | null)[], unknown, unknown>>;
readonly required: false;
readonly validator: ((val: unknown) => boolean) | undefined;
__epPropKey: true;
};
};
/**
* @deprecated Removed after 3.0.0, Use `ImageProps` instead.
*/
type ImagePropsPublic = ExtractPublicPropTypes<typeof imageProps>;
declare const imageEmits: {
load: (evt: Event) => boolean;
error: (evt: Event) => boolean;
switch: (val: number) => boolean;
close: () => boolean;
show: () => boolean;
};
type ImageEmits = typeof imageEmits;
type ImageInstance = InstanceType<typeof _default> & unknown;
//#endregion
export { ImageCrossorigin, ImageEmits, ImageFitType, ImageInstance, ImageProps, ImagePropsPublic, imageEmits, imageProps };
+82
View File
@@ -0,0 +1,82 @@
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_types = require('../../../utils/types.js');
const require_runtime = require('../../../utils/vue/props/runtime.js');
const require_typescript = require('../../../utils/typescript.js');
//#region ../../packages/components/image/src/image.ts
/**
* @deprecated Removed after 3.0.0, Use `ImageProps` instead.
*/
const imageProps = require_runtime.buildProps({
hideOnClickModal: Boolean,
src: {
type: String,
default: ""
},
fit: {
type: String,
values: [
"",
"contain",
"cover",
"fill",
"none",
"scale-down"
],
default: ""
},
loading: {
type: String,
values: ["eager", "lazy"]
},
lazy: Boolean,
scrollContainer: { type: require_runtime.definePropType([String, Object]) },
previewSrcList: {
type: require_runtime.definePropType(Array),
default: () => require_typescript.mutable([])
},
previewTeleported: Boolean,
zIndex: { type: Number },
initialIndex: {
type: Number,
default: 0
},
infinite: {
type: Boolean,
default: true
},
closeOnPressEscape: {
type: Boolean,
default: true
},
zoomRate: {
type: Number,
default: 1.2
},
scale: {
type: Number,
default: 1
},
minScale: {
type: Number,
default: .2
},
maxScale: {
type: Number,
default: 7
},
showProgress: Boolean,
crossorigin: { type: require_runtime.definePropType(String) }
});
const imageEmits = {
load: (evt) => evt instanceof Event,
error: (evt) => evt instanceof Event,
switch: (val) => require_types.isNumber(val),
close: () => true,
show: () => true
};
//#endregion
exports.imageEmits = imageEmits;
exports.imageProps = imageProps;
//# sourceMappingURL=image.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,69 @@
import { ImageViewerAction } from "../../image-viewer/src/image-viewer.js";
import "../../image-viewer/index.js";
import { ImageFitType, ImageProps } from "./image.js";
import * as vue from "vue";
//#region ../../packages/components/image/src/image.vue.d.ts
declare function clickHandler(): void;
declare var __VLS_1: {}, __VLS_3: {}, __VLS_14: {}, __VLS_17: {
activeIndex: number;
total: number;
}, __VLS_20: {
actions: (action: ImageViewerAction, options?: {}) => void;
prev: () => void;
next: () => void;
reset: () => void;
activeIndex: number;
setActiveItem: (index: number) => void;
}, __VLS_23: {
activeIndex: number;
src: string;
};
type __VLS_Slots = {} & {
error?: (props: typeof __VLS_1) => any;
} & {
placeholder?: (props: typeof __VLS_3) => any;
} & {
viewer?: (props: typeof __VLS_14) => any;
} & {
progress?: (props: typeof __VLS_17) => any;
} & {
toolbar?: (props: typeof __VLS_20) => any;
} & {
'viewer-error'?: (props: typeof __VLS_23) => any;
};
declare const __VLS_base: vue.DefineComponent<ImageProps, {
/** @description manually open preview */showPreview: typeof clickHandler;
}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
close: () => void;
error: (evt: Event) => void;
load: (evt: Event) => void;
show: () => void;
switch: (val: number) => void;
}, string, vue.PublicProps, Readonly<ImageProps> & Readonly<{
onClose?: (() => any) | undefined;
onError?: ((evt: Event) => any) | undefined;
onLoad?: ((evt: Event) => any) | undefined;
onShow?: (() => any) | undefined;
onSwitch?: ((val: number) => any) | undefined;
}>, {
infinite: boolean;
scale: number;
src: string;
fit: ImageFitType;
initialIndex: number;
closeOnPressEscape: boolean;
previewSrcList: string[];
zoomRate: number;
minScale: number;
maxScale: number;
}, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
declare const _default: typeof __VLS_export;
type __VLS_WithSlots<T, S> = T & {
new (): {
$slots: S;
};
};
//#endregion
export { _default };
@@ -0,0 +1,209 @@
const require_runtime = require('../../../_virtual/_rolldown/runtime.js');
const require_types = require('../../../utils/types.js');
const require_scroll = require('../../../utils/dom/scroll.js');
const require_index = require('../../../hooks/use-attrs/index.js');
const require_index$1 = require('../../../hooks/use-locale/index.js');
const require_index$2 = require('../../../hooks/use-namespace/index.js');
const require_image = require('./image.js');
const require_index$3 = require('../../image-viewer/index.js');
let _vueuse_core = require("@vueuse/core");
let lodash_unified = require("lodash-unified");
let vue = require("vue");
let _vue_shared = require("@vue/shared");
//#region ../../packages/components/image/src/image.vue?vue&type=script&setup=true&lang.ts
const _hoisted_1 = [
"src",
"loading",
"crossorigin"
];
const _hoisted_2 = { key: 0 };
var image_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
name: "ElImage",
inheritAttrs: false,
__name: "image",
props: require_image.imageProps,
emits: require_image.imageEmits,
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
const { t } = require_index$1.useLocale();
const ns = require_index$2.useNamespace("image");
const rawAttrs = (0, vue.useAttrs)();
const containerAttrs = (0, vue.computed)(() => {
return (0, lodash_unified.fromPairs)(Object.entries(rawAttrs).filter(([key]) => /^(data-|on[A-Z])/i.test(key) || ["id", "style"].includes(key)));
});
const imgAttrs = require_index.useAttrs({
excludeListeners: true,
excludeKeys: (0, vue.computed)(() => {
return Object.keys(containerAttrs.value);
})
});
const imageSrc = (0, vue.ref)();
const hasLoadError = (0, vue.ref)(false);
const isLoading = (0, vue.ref)(true);
const showViewer = (0, vue.ref)(false);
const container = (0, vue.ref)();
const _scrollContainer = (0, vue.ref)();
const supportLoading = _vueuse_core.isClient && "loading" in HTMLImageElement.prototype;
let stopScrollListener;
const imageKls = (0, vue.computed)(() => [
ns.e("inner"),
preview.value && ns.e("preview"),
isLoading.value && ns.is("loading")
]);
const imageStyle = (0, vue.computed)(() => {
const { fit } = props;
if (_vueuse_core.isClient && fit) return { objectFit: fit };
return {};
});
const preview = (0, vue.computed)(() => {
const { previewSrcList } = props;
return (0, _vue_shared.isArray)(previewSrcList) && previewSrcList.length > 0;
});
const imageIndex = (0, vue.computed)(() => {
const { previewSrcList, initialIndex } = props;
let previewIndex = initialIndex;
if (initialIndex > previewSrcList.length - 1) previewIndex = 0;
return previewIndex;
});
const isManual = (0, vue.computed)(() => {
if (props.loading === "eager") return false;
return !supportLoading && props.loading === "lazy" || props.lazy;
});
const loadImage = () => {
if (!_vueuse_core.isClient) return;
isLoading.value = true;
hasLoadError.value = false;
imageSrc.value = props.src;
};
function handleLoad(event) {
isLoading.value = false;
hasLoadError.value = false;
emit("load", event);
}
function handleError(event) {
isLoading.value = false;
hasLoadError.value = true;
emit("error", event);
}
function handleLazyLoad(isIntersecting) {
if (isIntersecting) {
loadImage();
removeLazyLoadListener();
}
}
const lazyLoadHandler = (0, _vueuse_core.useThrottleFn)(handleLazyLoad, 200, true);
async function addLazyLoadListener() {
if (!_vueuse_core.isClient) return;
await (0, vue.nextTick)();
const { scrollContainer } = props;
if (require_types.isElement(scrollContainer)) _scrollContainer.value = scrollContainer;
else if ((0, _vue_shared.isString)(scrollContainer) && scrollContainer !== "") _scrollContainer.value = document.querySelector(scrollContainer) ?? void 0;
else if (container.value) {
const scrollContainer = require_scroll.getScrollContainer(container.value);
_scrollContainer.value = require_types.isWindow(scrollContainer) ? void 0 : scrollContainer;
}
const { stop } = (0, _vueuse_core.useIntersectionObserver)(container, ([entry]) => {
lazyLoadHandler(entry.isIntersecting);
}, { root: _scrollContainer });
stopScrollListener = stop;
}
function removeLazyLoadListener() {
if (!_vueuse_core.isClient || !lazyLoadHandler) return;
stopScrollListener?.();
_scrollContainer.value = void 0;
stopScrollListener = void 0;
}
function clickHandler() {
if (!preview.value) return;
showViewer.value = true;
emit("show");
}
function closeViewer() {
showViewer.value = false;
emit("close");
}
function switchViewer(val) {
emit("switch", val);
}
(0, vue.watch)(() => props.src, () => {
if (isManual.value) {
isLoading.value = true;
hasLoadError.value = false;
removeLazyLoadListener();
addLazyLoadListener();
} else loadImage();
});
(0, vue.onMounted)(() => {
if (isManual.value) addLazyLoadListener();
else loadImage();
});
__expose({ showPreview: clickHandler });
return (_ctx, _cache) => {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", (0, vue.mergeProps)({
ref_key: "container",
ref: container
}, containerAttrs.value, { class: [(0, vue.unref)(ns).b(), _ctx.$attrs.class] }), [hasLoadError.value ? (0, vue.renderSlot)(_ctx.$slots, "error", { key: 0 }, () => [(0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)((0, vue.unref)(ns).e("error")) }, (0, vue.toDisplayString)((0, vue.unref)(t)("el.image.error")), 3)]) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [imageSrc.value !== void 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", (0, vue.mergeProps)({ key: 0 }, (0, vue.unref)(imgAttrs), {
src: imageSrc.value,
loading: __props.loading,
style: imageStyle.value,
class: imageKls.value,
crossorigin: __props.crossorigin,
onClick: clickHandler,
onLoad: handleLoad,
onError: handleError
}), null, 16, _hoisted_1)) : (0, vue.createCommentVNode)("v-if", true), isLoading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
key: 1,
class: (0, vue.normalizeClass)((0, vue.unref)(ns).e("wrapper"))
}, [(0, vue.renderSlot)(_ctx.$slots, "placeholder", {}, () => [(0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)((0, vue.unref)(ns).e("placeholder")) }, null, 2)])], 2)) : (0, vue.createCommentVNode)("v-if", true)], 64)), preview.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [showViewer.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(require_index$3.ElImageViewer), {
key: 0,
"z-index": __props.zIndex,
"initial-index": imageIndex.value,
infinite: __props.infinite,
"zoom-rate": __props.zoomRate,
"min-scale": __props.minScale,
"max-scale": __props.maxScale,
"show-progress": __props.showProgress,
"url-list": __props.previewSrcList,
scale: __props.scale,
crossorigin: __props.crossorigin,
"hide-on-click-modal": __props.hideOnClickModal,
teleported: __props.previewTeleported,
"close-on-press-escape": __props.closeOnPressEscape,
onClose: closeViewer,
onSwitch: switchViewer
}, (0, vue.createSlots)({
toolbar: (0, vue.withCtx)((toolbar) => [(0, vue.renderSlot)(_ctx.$slots, "toolbar", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(toolbar)))]),
default: (0, vue.withCtx)(() => [_ctx.$slots.viewer ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2, [(0, vue.renderSlot)(_ctx.$slots, "viewer")])) : (0, vue.createCommentVNode)("v-if", true)]),
_: 2
}, [_ctx.$slots.progress ? {
name: "progress",
fn: (0, vue.withCtx)((progress) => [(0, vue.renderSlot)(_ctx.$slots, "progress", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(progress)))]),
key: "0"
} : void 0, _ctx.$slots["viewer-error"] ? {
name: "viewer-error",
fn: (0, vue.withCtx)((viewerError) => [(0, vue.renderSlot)(_ctx.$slots, "viewer-error", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(viewerError)))]),
key: "1"
} : void 0]), 1032, [
"z-index",
"initial-index",
"infinite",
"zoom-rate",
"min-scale",
"max-scale",
"show-progress",
"url-list",
"scale",
"crossorigin",
"hide-on-click-modal",
"teleported",
"close-on-press-escape"
])) : (0, vue.createCommentVNode)("v-if", true)], 64)) : (0, vue.createCommentVNode)("v-if", true)], 16);
};
}
});
//#endregion
exports.default = image_vue_vue_type_script_setup_true_lang_default;
//# sourceMappingURL=image.vue_vue_type_script_setup_true_lang.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const require_image_vue_vue_type_script_setup_true_lang = require('./image.vue_vue_type_script_setup_true_lang.js');
//#region ../../packages/components/image/src/image.vue
var image_default = require_image_vue_vue_type_script_setup_true_lang.default;
//#endregion
exports.default = image_default;
//# sourceMappingURL=image2.js.map
File diff suppressed because one or more lines are too long
+4
View File
@@ -0,0 +1,4 @@
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
require('../../base/style/css.js');
require('../../image-viewer/style/css.js');
require("element-plus/theme-chalk/el-image.css");
@@ -0,0 +1,4 @@
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
require('../../base/style/index.js');
require('../../image-viewer/style/index.js');
require("element-plus/theme-chalk/src/image.scss");