<!-- CollapseTransition.vue -->
<template>
    <view :style="wrapStyle" class="collapse-wrapper">
        <view ref="contentRef" class="content-inner">
            <slot />
        </view>
    </view>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue';

const props = defineProps({
    show: Boolean,
    duration: {
        type: Number,
        default: 300,
    },
});

const wrapStyle = ref({
    height: '0rpx',
    opacity: 0,
    overflow: 'hidden',
    transition: `all ${props.duration}ms ease`,
});

const contentRef = ref(null);

// 获取高度（兼容 H5 + 小程序）
function getContentHeight() {
    return new Promise((resolve) => {
        const query = uni.createSelectorQuery().in(this ? this : undefined);
        query
            .select('.content-inner')
            .boundingClientRect((data) => {
                resolve(data?.height || 0);
            })
            .exec();
    });
}

// 动画执行
async function expand() {
    const height = await getContentHeight();
    wrapStyle.value = {
        height: height + 'px',
        opacity: 1,
        overflow: 'hidden',
        transition: `all ${props.duration}ms ease`,
    };

    setTimeout(() => {
        wrapStyle.value.height = 'auto';
    }, props.duration);
}

async function collapse() {
    const height = await getContentHeight();
    wrapStyle.value = {
        height: height + 'px',
        opacity: 1,
        overflow: 'hidden',
        transition: 'none',
    };

    // 等待下一帧开始收起动画
    await nextTick();
    requestAnimationFrame(() => {
        wrapStyle.value = {
            height: '0rpx',
            opacity: 0,
            overflow: 'hidden',
            transition: `all ${props.duration}ms ease`,
        };
    });
}

watch(
    () => props.show,
    (val) => {
        if (val) expand();
        else collapse();
    }
);
</script>

<style scoped>
.collapse-wrapper {
    width: 100%;
}
</style>
