UNPKG

@fesjs/fes-design

Version:
228 lines (221 loc) 9.07 kB
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 };