<!--
    Transitions between two items from a collection without the requirement of pre-rendering of all
    items. It does this by maintaing a dynamic collection of items and using TransitionGroup.

    Example (would crossfade a background image based on the selected item):

        <PxTransitionItem
            :class="bem('background')"
            :item="selectedBackgroundImage"
        >
            <template #default="{ item }">
                <div
                    :class="bem('background-image')"
                    :style="{ backgroundImage: cssUrl(item) }"
                />
            </template>
        </PxTransitionItem>



-->
<template>
    <transition-group
        :class="bem()"
        :name="transitionName ? transitionName : 'px-transition-item__fade'"
        tag="div"
        @before-leave="onBeforeLeave"
    >
        <div
            :class="[bem('item'), itemClass]"
            v-for="item in items"
            :key="item.id"
            :style="{
                transitionDuration: transitionDurationMs ? transitionDurationMs + 'ms' : null,
            }"
        >
            <slot :item="item.item" name="default" />
        </div>
    </transition-group>
</template>

<script>
import { getClientRect } from '../utils/utils.js';

export default {
    name: 'px-transition-item',
    props: {
        item: { default: null },
        itemClass: { default: null },
        transitionName: { default: null },
        transitionDurationMs: { type: Number, default: null },
        pin: { type: Boolean, default: false },
    },
    data() {
        return { items: [], currentId: 0 };
    },
    watch: {
        item: {
            immediate: true,
            handler(nv, ov) {
                // compare similar objects

                if (nv && ov && typeof nv == 'object' && typeof ov == 'object') {
                    const nvstr = JSON.stringify(nv);
                    const ovstr = JSON.stringify(ov);

                    if (nvstr == ovstr) {
                        return;
                    }
                }

                if (ov && this.items.length) {
                    this.items.shift();
                }

                if (nv) {
                    this.items.push({ id: this.currentId++, item: nv });
                }
            },
        },
    },
    methods: {
        onBeforeLeave(el) {
            if (this.pin) {
                let r = getClientRect(el);
                el.style.position = 'fixed';
                el.style.top = r.top + 'px';
                el.style.left = r.left + 'px';
                el.style.width = r.width + 'px';
                el.style.height = r.height + 'px';
            }
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;

// background change transition
@include vue-transition-fade(px-transition-item__fade, $dur: 0.5s, $pin: true);

.px-transition-item {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);

    &__item {
        grid-area: 1 / 1;
    }
}
</style>
