<!-- 基础模态框组件 -->
<template>
    <teleport :to="teleport">
        <div class="app-modal" v-bind="$attrs" :style="modalStyles" v-show="visible">
            <div :class="['app-modal__mask', transitionClass]" :style="transitionStyles"></div>
            <div :class="['app-modal__wrapper', direction]" @click.self="onMask">
                <div :class="['app-modal__container', transitionClass]" :style="containerStyles">
                    <slot :animation="animation"></slot>
                </div>
            </div>
        </div>
    </teleport>
</template>

<script lang="ts">
import { defineComponent, computed, watch, PropType } from 'vue'
import { useModal } from './index'

export default defineComponent({
    inheritAttrs: false,
    emits: ['mask', 'opened', 'closed'],
    props: {
        show: {
            type: Boolean,
            default: false,
        },
        // 窗口关闭后是否刷新
        refresh: {
            type: Boolean,
            default: false,
        },
        // 是否可以点击遮罩关闭窗口
        closeOnClickMask: {
            type: Boolean,
            default: true,
        },
        // 窗口插入到指定元素
        teleport: {
            type: String,
            default: 'body',
        },
        // 绝对定位
        fixed: {
            type: Boolean,
            default: true,
        },
        // 遮罩堆叠顺序
        zIndex: {
            type: Number,
            default: 1000,
        },
        // 窗口动画时间
        delay: {
            type: Number,
            default: 300,
        },
        // 窗口弹出方向
        direction: {
            type: String as PropType<'full' | 'center' | 'left' | 'right' | 'top' | 'bottom' | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom'>,
            default: 'center',
        },
        // 窗口宽度
        width: {
            type: [Number, String],
            default: 'auto',
        },
        // 窗口高度
        height: {
            type: [Number, String],
            default: 'auto',
        },
    },
    setup(props, { emit }) {
        const { visible, animation, transitionClass, transitionStyles, transition } = useModal(props.show, props.delay);

        const modalStyles = computed(() => ({
            position: props.fixed ? 'fixed' : 'absolute',
            zIndex: props.zIndex,
        }))

        const containerStyles = computed(() => {
            const getWidth = () => {
                const width = props.width.toString();
                if (width.endsWith('%')) {
                    return width;
                }
                return width === 'auto' ? width : width + 'px';
            }
            const getHeight = () => {
                const height = props.height.toString();
                if (height.endsWith('%')) {
                    return height;
                }
                return height === 'auto' ? height : height + 'px';
            }
            return {
                ...transitionStyles.value,
                width: getWidth(),
                height: getHeight(),
            }
        })

        // 点击遮罩事件
        const onMask = () => {
            if (props.closeOnClickMask) {
                emit('mask');
            }
        }

        watch(() => props.show, (isShow) => {
            transition(isShow, () => {
                if (isShow) {
                    emit('opened');
                } else {
                    emit('closed', props.refresh);
                }
            })
        })

        return {
            visible,
            animation,
            transitionClass,
            transitionStyles,
            modalStyles,
            containerStyles,
            onMask,
        }
    }
})
</script>

<style lang="less">
@import './index.less';
</style>