naive-ui
Version:
A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast
186 lines • 6.14 kB
JavaScript
import { createId } from 'seemly';
import { useMergedState } from 'vooks';
import { computed, defineComponent, h, provide, ref, toRef } from 'vue';
import { useConfig } from "../../_mixins/index.mjs";
import { call, createInjectionKey, throwError } from "../../_utils/index.mjs";
import NImagePreview from "./ImagePreview.mjs";
import { imagePreviewSharedProps } from "./interface.mjs";
export const imageGroupInjectionKey = createInjectionKey('n-image-group');
export const imageGroupProps = Object.assign(Object.assign({}, imagePreviewSharedProps), {
srcList: Array,
current: Number,
defaultCurrent: {
type: Number,
default: 0
},
show: {
type: Boolean,
default: undefined
},
defaultShow: Boolean,
onUpdateShow: [Function, Array],
'onUpdate:show': [Function, Array],
onUpdateCurrent: [Function, Array],
'onUpdate:current': [Function, Array]
});
export default defineComponent({
name: 'ImageGroup',
props: imageGroupProps,
setup(props) {
const {
mergedClsPrefixRef
} = useConfig(props);
const groupId = `c${createId()}`;
const previewInstRef = ref(null);
const uncontrolledShowRef = ref(props.defaultShow);
const controlledShowRef = toRef(props, 'show');
const mergedShowRef = useMergedState(controlledShowRef, uncontrolledShowRef);
const registeredImageUrlMap = ref(new Map());
const mergedImageUrlMap = computed(() => {
if (props.srcList) {
const map = new Map();
props.srcList.forEach((url, index) => {
map.set(`p${index}`, url);
});
return map;
}
return registeredImageUrlMap.value;
});
const imageIdListRef = computed(() => Array.from(mergedImageUrlMap.value.keys()));
const imageCountGetter = () => imageIdListRef.value.length;
function registerImageUrl(id, url) {
if (props.srcList) {
throwError('image-group', '`n-image` can\'t be placed inside `n-image-group` when image group\'s `src-list` prop is set.');
}
const sid = `r${id}`;
if (!registeredImageUrlMap.value.has(`r${sid}`)) {
registeredImageUrlMap.value.set(sid, url);
}
return function unregisterPreviewUrl() {
if (!registeredImageUrlMap.value.has(sid)) {
registeredImageUrlMap.value.delete(sid);
}
};
}
const uncontrolledCurrentRef = ref(props.defaultCurrent);
const controlledCurrentRef = toRef(props, 'current');
const mergedCurrentRef = useMergedState(controlledCurrentRef, uncontrolledCurrentRef);
const setCurrentIndex = index => {
if (index !== mergedCurrentRef.value) {
const {
onUpdateCurrent,
'onUpdate:current': _onUpdateCurrent
} = props;
if (onUpdateCurrent) {
call(onUpdateCurrent, index);
}
if (_onUpdateCurrent) {
call(_onUpdateCurrent, index);
}
uncontrolledCurrentRef.value = index;
}
};
const currentId = computed(() => imageIdListRef.value[mergedCurrentRef.value]);
const setCurrentId = nextId => {
const nextIndex = imageIdListRef.value.indexOf(nextId);
if (nextIndex !== mergedCurrentRef.value) {
setCurrentIndex(nextIndex);
}
};
const currentUrl = computed(() => mergedImageUrlMap.value.get(currentId.value));
function doUpdateShow(value) {
const {
onUpdateShow,
'onUpdate:show': _onUpdateShow
} = props;
if (onUpdateShow) {
call(onUpdateShow, value);
}
if (_onUpdateShow) {
call(_onUpdateShow, value);
}
uncontrolledShowRef.value = value;
}
function onClose() {
doUpdateShow(false);
}
const nextIndex = computed(() => {
const findNext = (start, end) => {
for (let i = start; i <= end; i++) {
const id = imageIdListRef.value[i];
if (mergedImageUrlMap.value.get(id)) {
return i;
}
}
return undefined;
};
const next = findNext(mergedCurrentRef.value + 1, imageCountGetter() - 1);
return next === undefined ? findNext(0, mergedCurrentRef.value - 1) : next;
});
const prevIndex = computed(() => {
const findPrev = (start, end) => {
for (let i = start; i >= end; i--) {
const id = imageIdListRef.value[i];
if (mergedImageUrlMap.value.get(id)) {
return i;
}
}
return undefined;
};
const prev = findPrev(mergedCurrentRef.value - 1, 0);
return prev === undefined ? findPrev(imageCountGetter() - 1, mergedCurrentRef.value + 1) : prev;
});
function go(step) {
var _a, _b;
if (step === 1) {
prevIndex.value !== undefined && setCurrentIndex(nextIndex.value);
(_a = props.onPreviewNext) === null || _a === void 0 ? void 0 : _a.call(props);
} else {
nextIndex.value !== undefined && setCurrentIndex(prevIndex.value);
(_b = props.onPreviewPrev) === null || _b === void 0 ? void 0 : _b.call(props);
}
}
provide(imageGroupInjectionKey, {
mergedClsPrefixRef,
registerImageUrl,
setThumbnailEl: el => {
var _a;
(_a = previewInstRef.value) === null || _a === void 0 ? void 0 : _a.setThumbnailEl(el);
},
toggleShow: imageId => {
doUpdateShow(true);
setCurrentId(imageId);
},
groupId,
renderToolbarRef: toRef(props, 'renderToolbar')
});
return {
mergedClsPrefix: mergedClsPrefixRef,
previewInstRef,
mergedShow: mergedShowRef,
src: currentUrl,
onClose,
next: () => {
go(1);
},
prev: () => {
go(-1);
}
};
},
render() {
return h(NImagePreview, {
theme: this.theme,
themeOverrides: this.themeOverrides,
ref: "previewInstRef",
onPrev: this.prev,
onNext: this.next,
src: this.src,
show: this.mergedShow,
showToolbar: this.showToolbar,
showToolbarTooltip: this.showToolbarTooltip,
renderToolbar: this.renderToolbar,
onClose: this.onClose
}, this.$slots);
}
});