```vue
<script setup>
import { ref, watch, onBeforeUnmount } from 'vue';
import {
    CheckCircle2,
    XCircle,
    AlertTriangle,
    Info,
    X,
} from 'lucide-vue-next';

const props = defineProps({
    show: {
        type: Boolean,
        default: false,
    },
    message: {
        type: String,
        default: '',
    },
    type: {
        type: String,
        default: 'success',
    },
    duration: {
        type: Number,
        default: 3000,
    },
});

const emit = defineEmits(['close']);

const progress = ref(100);
let timer = null;
let progressTimer = null;

const config = {
    success: {
        title: 'Berhasil! 🎉',
        icon: CheckCircle2,
        iconClass: 'bg-emerald-50 text-emerald-600',
        progressClass: 'bg-emerald-500',
    },
    error: {
        title: 'Oops! 😅',
        icon: XCircle,
        iconClass: 'bg-red-50 text-red-600',
        progressClass: 'bg-red-500',
    },
    warning: {
        title: 'Perhatian! 👀',
        icon: AlertTriangle,
        iconClass: 'bg-amber-50 text-amber-600',
        progressClass: 'bg-amber-500',
    },
    info: {
        title: 'Info 💡',
        icon: Info,
        iconClass: 'bg-blue-50 text-blue-600',
        progressClass: 'bg-blue-500',
    },
};

const currentConfig = () => {
    return config[props.type] || config.success;
};

const close = () => {
    clearTimers();
    emit('close');
};

const clearTimers = () => {
    if (timer) {
        clearTimeout(timer);
        timer = null;
    }

    if (progressTimer) {
        clearInterval(progressTimer);
        progressTimer = null;
    }
};

const startTimer = () => {
    clearTimers();

    progress.value = 100;

    const interval = 50;
    const totalSteps = props.duration / interval;
    const decrement = 100 / totalSteps;

    progressTimer = setInterval(() => {
        progress.value -= decrement;

        if (progress.value <= 0) {
            progress.value = 0;
            clearInterval(progressTimer);
            progressTimer = null;
        }
    }, interval);

    timer = setTimeout(() => {
        close();
    }, props.duration);
};

watch(
    () => props.show,
    (show) => {
        if (show) {
            startTimer();
        } else {
            clearTimers();
        }
    }
);

onBeforeUnmount(() => {
    clearTimers();
});
</script>

<template>

    <Teleport to="body">

        <Transition name="toast">

            <div v-if="show" class="fixed top-5 right-5 z-50 w-full max-w-sm mr-5">

                <div class="relative overflow-hidden
                           bg-white
                           border border-gray-100
                           rounded-2xl
                           shadow-xl">

                    <!-- Isi Toast -->
                    <div class="flex items-start gap-3 p-4">

                        <!-- Icon -->
                        <div class="w-10 h-10
                                   flex items-center justify-center
                                   rounded-xl
                                   shrink-0" :class="currentConfig().iconClass">
                            <component :is="currentConfig().icon" :size="20" :stroke-width="2.2" />
                        </div>

                        <!-- Pesan -->
                        <div class="flex-1 min-w-0 pt-0.5">

                            <h3 class="text-sm font-bold text-gray-800">
                                {{ currentConfig().title }}
                            </h3>

                            <p class="text-xs text-gray-500 mt-1 leading-5">
                                {{ message }}
                            </p>

                        </div>

                        <!-- Close -->
                        <button type="button" @click="close" class="w-7 h-7
                                   flex items-center justify-center
                                   rounded-lg
                                   text-gray-400
                                   hover:text-gray-600
                                   hover:bg-gray-100
                                   transition
                                   shrink-0" title="Tutup">
                            <X :size="15" />
                        </button>

                    </div>

                    <!-- Progress Bar -->
                    <div class="absolute bottom-0 left-0 w-full h-1 bg-gray-100">

                        <div class="h-full transition-[width] duration-50 ease-linear"
                            :class="currentConfig().progressClass" :style="{ width: `${progress}%` }"></div>

                    </div>

                </div>

            </div>

        </Transition>

    </Teleport>

</template>

<style scoped>
.toast-enter-active,
.toast-leave-active {
    transition:
        transform 0.3s ease,
        opacity 0.3s ease;
}

.toast-enter-from,
.toast-leave-to {
    transform: translateX(120%);
    opacity: 0;
}

.toast-enter-to,
.toast-leave-from {
    transform: translateX(0);
    opacity: 1;
}
</style>
```
