@fesjs/fes-design
Version:
fes-design for PC
228 lines (221 loc) • 9.07 kB
JavaScript
import { defineComponent, ref, watch, nextTick, computed, createVNode, Teleport, Fragment, Transition, withDirectives, vShow } from 'vue';
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { isNumber } from 'lodash-es';
import getPrefixCls from '../_util/getPrefixCls';
import { FScrollbar } from '../scrollbar';
import FButton from '../button/button';
import { CloseOutlined } from '../icon';
import { useTheme } from '../_theme/useTheme';
import useEsc from '../_util/use/useEsc';
import PopupManager from '../_util/popupManager';
import useLockScreen from '../_util/use/useLockScreen';
import { useConfig } from '../config-provider';
import { useLocale } from '../config-provider/useLocale';
import { useContentMaxHeight } from './useContentMaxHeight';
import { globalModalProps, modalProps, modalIconMap } from './props';
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const prefixCls = getPrefixCls('modal');
const UPDATE_SHOW_EVENT = 'update:show';
const OK_EVENT = 'ok';
const CANCEL_EVENT = 'cancel';
const AFTER_ENTER_EVENT = 'after-enter';
const AFTER_LEAVE_EVENT = 'after-leave';
const Modal = defineComponent({
name: 'FModal',
props: _objectSpread(_objectSpread({}, globalModalProps), modalProps),
emits: [UPDATE_SHOW_EVENT, OK_EVENT, CANCEL_EVENT, AFTER_ENTER_EVENT, AFTER_LEAVE_EVENT],
setup(props, ctx) {
useTheme();
const zIndex = ref(PopupManager.nextZIndex());
const visible = ref(false);
useLockScreen(visible);
watch(() => props.show, () => {
if (props.show) {
zIndex.value = PopupManager.nextZIndex();
}
nextTick(() => {
visible.value = props.show;
});
}, {
immediate: true
});
const config = useConfig();
const getContainer = computed(() => {
var _config$getContainer;
return props.getContainer || ((_config$getContainer = config.getContainer) === null || _config$getContainer === void 0 ? void 0 : _config$getContainer.value);
});
const {
t
} = useLocale();
function handleCancel(event) {
ctx.emit(UPDATE_SHOW_EVENT, false);
ctx.emit(CANCEL_EVENT, event);
}
const escClosable = computed(() => props.escClosable);
useEsc(handleCancel, escClosable);
function handleOk(event) {
ctx.emit(OK_EVENT, event);
}
function handleTransitionAfterEnter(el) {
ctx.emit(AFTER_ENTER_EVENT, el);
}
function handleTransitionAfterLeave(el) {
ctx.emit(AFTER_LEAVE_EVENT, el);
}
const hasHeader = () => ctx.slots.title || props.title;
function getHeader() {
var _ctx$slots$title, _ctx$slots;
const closeJsx = props.closable && createVNode("div", {
"class": `${prefixCls}-close`,
"onClick": handleCancel
}, [createVNode(CloseOutlined, null, null)]);
if (!hasHeader()) {
return closeJsx;
}
const header = ((_ctx$slots$title = (_ctx$slots = ctx.slots).title) === null || _ctx$slots$title === void 0 ? void 0 : _ctx$slots$title.call(_ctx$slots)) || props.title;
return createVNode("div", {
"class": `${prefixCls}-header`,
"ref": modalHeaderRef
}, [props.type && createVNode("div", {
"class": `${prefixCls}-icon ${prefixCls}-status-${props.type}`
}, [props.type && modalIconMap[props.type]()]), createVNode("div", null, [header]), closeJsx]);
}
function getFooter() {
if (!props.footer) {
return null;
}
let footer = null;
if (ctx.slots.footer) {
footer = ctx.slots.footer();
} else {
footer = createVNode(Fragment, null, [props.showCancel && createVNode(FButton, {
"size": "middle",
"class": "btn-margin",
"onClick": handleCancel,
"loading": props.cancelLoading
}, {
default: () => [props.cancelText || t('modal.cancelText')]
}), createVNode(FButton, {
"type": "primary",
"size": "middle",
"onClick": handleOk,
"loading": props.okLoading
}, {
default: () => [props.okText || t('modal.okText')]
})]);
}
return createVNode("div", {
"class": `${prefixCls}-footer`,
"ref": modalFooterRef
}, [footer]);
}
const styles = computed(() => {
if (props.fullScreen) {
return {};
}
return {
width: isNumber(props.width) ? `${props.width}px` : props.width,
marginTop: props.verticalCenter ? 0 : isNumber(props.top) ? `${props.top}px` : props.top,
marginBottom: props.verticalCenter ? 0 : isNumber(props.bottom) ? `${props.bottom}px` : props.bottom
};
});
// 获取最大的内容高度
const {
modalRef,
modalHeaderRef,
modalFooterRef,
contentMaxHeight,
hasMaxHeight
} = useContentMaxHeight(styles, props);
const getBody = () => {
const modalBody = createVNode("div", {
"class": `${prefixCls}-body`
}, [ctx.slots.default ? ctx.slots.default() : props.forGlobal && props.content]);
if (hasMaxHeight.value) {
return createVNode(FScrollbar, {
"maxHeight": contentMaxHeight.value,
"shadow": true
}, {
default: () => [modalBody]
});
}
return modalBody;
};
const showDom = computed(() => props.displayDirective === 'if' && visible.value || props.displayDirective === 'show');
// 鼠标在弹窗内按下
const mouseDownInsideChild = ref(false);
// 遮罩层点击关闭的逻辑
const handleClickMask = event => {
if (props.maskClosable && props.mask && !mouseDownInsideChild.value) {
handleCancel(event);
}
mouseDownInsideChild.value = false;
};
// 最外层类名
const rootClass = computed(() => {
return [prefixCls, props.wrapperClass].filter(Boolean);
});
const wrapperClass = computed(() => {
return [`${prefixCls}-wrapper`, props.contentClass].filter(Boolean);
});
const renderMask = () => {
return withDirectives(createVNode("div", {
"class": `${prefixCls}-mask`,
"style": {
zIndex: zIndex.value
}
}, null), [[vShow, visible.value]]);
};
const renderContent = () => {
return withDirectives(createVNode("div", {
"class": {
[`${prefixCls}-container`]: true,
[`${prefixCls}-center`]: props.center,
[`${prefixCls}-vertical-center`]: props.verticalCenter,
[`${prefixCls}-fullscreen`]: props.fullScreen,
[`${prefixCls}-global`]: props.forGlobal,
[`${prefixCls}-no-header`]: !hasHeader(),
[`${prefixCls}-no-footer`]: !props.footer
},
"style": {
zIndex: zIndex.value
},
"onClick": event => handleClickMask(event)
}, [createVNode("div", {
"class": wrapperClass.value,
"style": styles.value,
"onClick": event => event.stopPropagation(),
"onMousedown": () => {
mouseDownInsideChild.value = true;
},
"onMouseup": () => {
mouseDownInsideChild.value = false;
},
"ref": modalRef
}, [getHeader(), getBody(), getFooter()])]), [[vShow, visible.value]]);
};
return () => {
var _getContainer$value, _getContainer$value2;
return createVNode(Teleport, {
"disabled": !((_getContainer$value = getContainer.value) !== null && _getContainer$value !== void 0 && _getContainer$value.call(getContainer)),
"to": (_getContainer$value2 = getContainer.value) === null || _getContainer$value2 === void 0 ? void 0 : _getContainer$value2.call(getContainer)
}, {
default: () => [createVNode("div", {
"class": rootClass.value
}, [props.useAnimation ? createVNode(Fragment, null, [createVNode(Transition, {
"name": `${prefixCls}-mask-fade`
}, {
default: () => [props.mask && showDom.value && renderMask()]
}), createVNode(Transition, {
"name": `${prefixCls}-fade`,
"onAfterEnter": handleTransitionAfterEnter,
"onAfterLeave": handleTransitionAfterLeave
}, {
default: () => [showDom.value && renderContent()]
})]) : createVNode(Fragment, null, [props.mask && showDom.value && renderMask(), showDom.value && renderContent()])])]
});
};
}
});
export { Modal as default };