UNPKG

naive-ui

Version:

A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast

298 lines 9.47 kB
import { clickoutside } from 'vdirs'; import { cloneVNode, computed, defineComponent, h, inject, mergeProps, nextTick, normalizeClass, provide, ref, toRef, Transition, vShow, watch, withDirectives } from 'vue'; import { VFocusTrap } from 'vueuc'; import { NScrollbar } from "../../_internal/index.mjs"; import { getFirstSlotVNodeWithTypedProps, keep, useLockHtmlScroll, warn } from "../../_utils/index.mjs"; import { NCard } from "../../card/index.mjs"; import { cardBasePropKeys } from "../../card/src/Card.mjs"; import { NDialog } from "../../dialog/src/Dialog.mjs"; import { dialogPropKeys } from "../../dialog/src/dialogProps.mjs"; import { drawerBodyInjectionKey } from "../../drawer/src/interface.mjs"; import { popoverBodyInjectionKey } from "../../popover/src/interface.mjs"; import { useDragModal } from "./composables.mjs"; import { modalBodyInjectionKey, modalInjectionKey } from "./interface.mjs"; import { presetProps } from "./presetProps.mjs"; export default defineComponent({ name: 'ModalBody', inheritAttrs: false, slots: Object, props: Object.assign(Object.assign({ show: { type: Boolean, required: true }, preset: String, displayDirective: { type: String, required: true }, trapFocus: { type: Boolean, default: true }, autoFocus: { type: Boolean, default: true }, blockScroll: Boolean, draggable: { type: [Boolean, Object], default: false } }, presetProps), { renderMask: Function, // events onClickoutside: Function, onBeforeLeave: { type: Function, required: true }, onAfterLeave: { type: Function, required: true }, onPositiveClick: { type: Function, required: true }, onNegativeClick: { type: Function, required: true }, onClose: { type: Function, required: true }, onAfterEnter: Function, onEsc: Function }), setup(props) { const bodyRef = ref(null); const scrollbarRef = ref(null); const displayedRef = ref(props.show); const transformOriginXRef = ref(null); const transformOriginYRef = ref(null); const NModal = inject(modalInjectionKey); let mousePosition = null; watch(toRef(props, 'show'), value => { if (value) { mousePosition = NModal.getMousePosition(); } }, { immediate: true }); const { stopDrag, startDrag, draggableRef, draggableClassRef } = useDragModal(toRef(props, 'draggable'), { onEnd: el => { syncTransformOrigin(el); } }); const dialogTitleClassRef = computed(() => { return normalizeClass([props.titleClass, draggableClassRef.value]); }); const cardHeaderClassRef = computed(() => { return normalizeClass([props.headerClass, draggableClassRef.value]); }); watch(toRef(props, 'show'), value => { if (value) displayedRef.value = true; }); useLockHtmlScroll(computed(() => props.blockScroll && displayedRef.value)); function styleTransformOrigin() { if (NModal.transformOriginRef.value === 'center') { return ''; } const { value: transformOriginX } = transformOriginXRef; const { value: transformOriginY } = transformOriginYRef; if (transformOriginX === null || transformOriginY === null) { return ''; } else if (scrollbarRef.value) { const scrollTop = scrollbarRef.value.containerScrollTop; return `${transformOriginX}px ${transformOriginY + scrollTop}px`; } return ''; } function syncTransformOrigin(el) { if (NModal.transformOriginRef.value === 'center') { return; } if (!mousePosition) { return; } if (!scrollbarRef.value) return; const scrollTop = scrollbarRef.value.containerScrollTop; const { offsetLeft, offsetTop } = el; const top = mousePosition.y; const left = mousePosition.x; transformOriginXRef.value = -(offsetLeft - left); transformOriginYRef.value = -(offsetTop - top - scrollTop); el.style.transformOrigin = styleTransformOrigin(); } function handleEnter(el) { void nextTick(() => { syncTransformOrigin(el); }); } function handleBeforeLeave(el) { el.style.transformOrigin = styleTransformOrigin(); props.onBeforeLeave(); } function handleAfterEnter(el) { const element = el; draggableRef.value && startDrag(element); props.onAfterEnter && props.onAfterEnter(element); } function handleAfterLeave() { displayedRef.value = false; transformOriginXRef.value = null; transformOriginYRef.value = null; stopDrag(); props.onAfterLeave(); } function handleCloseClick() { const { onClose } = props; if (onClose) { onClose(); } } function handleNegativeClick() { props.onNegativeClick(); } function handlePositiveClick() { props.onPositiveClick(); } const childNodeRef = ref(null); watch(childNodeRef, node => { if (node) { void nextTick(() => { const el = node.el; if (el && bodyRef.value !== el) { bodyRef.value = el; } }); } }); provide(modalBodyInjectionKey, bodyRef); provide(drawerBodyInjectionKey, null); provide(popoverBodyInjectionKey, null); return { mergedTheme: NModal.mergedThemeRef, appear: NModal.appearRef, isMounted: NModal.isMountedRef, mergedClsPrefix: NModal.mergedClsPrefixRef, bodyRef, scrollbarRef, draggableClass: draggableClassRef, displayed: displayedRef, childNodeRef, cardHeaderClass: cardHeaderClassRef, dialogTitleClass: dialogTitleClassRef, handlePositiveClick, handleNegativeClick, handleCloseClick, handleAfterEnter, handleAfterLeave, handleBeforeLeave, handleEnter }; }, render() { const { $slots, $attrs, handleEnter, handleAfterEnter, handleAfterLeave, handleBeforeLeave, preset, mergedClsPrefix } = this; let childNode = null; if (!preset) { childNode = getFirstSlotVNodeWithTypedProps('default', $slots.default, { draggableClass: this.draggableClass }); if (!childNode) { warn('modal', 'default slot is empty'); return; } childNode = cloneVNode(childNode); childNode.props = mergeProps({ class: `${mergedClsPrefix}-modal` }, $attrs, childNode.props || {}); } return this.displayDirective === 'show' || this.displayed || this.show ? withDirectives(h("div", { role: "none", class: `${mergedClsPrefix}-modal-body-wrapper` }, h(NScrollbar, { ref: "scrollbarRef", theme: this.mergedTheme.peers.Scrollbar, themeOverrides: this.mergedTheme.peerOverrides.Scrollbar, contentClass: `${mergedClsPrefix}-modal-scroll-content` }, { default: () => { var _a; return [(_a = this.renderMask) === null || _a === void 0 ? void 0 : _a.call(this), h(VFocusTrap, { disabled: !this.trapFocus, active: this.show, onEsc: this.onEsc, autoFocus: this.autoFocus }, { default: () => { var _a; return h(Transition, { name: "fade-in-scale-up-transition", appear: (_a = this.appear) !== null && _a !== void 0 ? _a : this.isMounted, onEnter: handleEnter, onAfterEnter: handleAfterEnter, onAfterLeave: handleAfterLeave, onBeforeLeave: handleBeforeLeave }, { default: () => { const dirs = [[vShow, this.show]]; const { onClickoutside } = this; if (onClickoutside) { dirs.push([clickoutside, this.onClickoutside, undefined, { capture: true }]); } return withDirectives(this.preset === 'confirm' || this.preset === 'dialog' ? h(NDialog, Object.assign({}, this.$attrs, { class: [`${mergedClsPrefix}-modal`, this.$attrs.class], ref: "bodyRef", theme: this.mergedTheme.peers.Dialog, themeOverrides: this.mergedTheme.peerOverrides.Dialog }, keep(this.$props, dialogPropKeys), { titleClass: this.dialogTitleClass, "aria-modal": "true" }), $slots) : this.preset === 'card' ? h(NCard, Object.assign({}, this.$attrs, { ref: "bodyRef", class: [`${mergedClsPrefix}-modal`, this.$attrs.class], theme: this.mergedTheme.peers.Card, themeOverrides: this.mergedTheme.peerOverrides.Card }, keep(this.$props, cardBasePropKeys), { headerClass: this.cardHeaderClass, "aria-modal": "true", role: "dialog" }), $slots) : this.childNodeRef = childNode, dirs); } }); } })]; } })), [[vShow, this.displayDirective === 'if' || this.displayed || this.show]]) : null; } });