<!--
    #VUE3 Todo

    Simple pivot component (basically tabs but uses an underline to show selection). Uses
    BaseItemsSelect so it can easily be paired with other BaseItemSelect components.

-->
<template>
    <div
        :class="bem({ animated: animated, loading: loading })"
        :style="{ opacity: loading ? 0 : null }"
    >
        <PxArrowScroller :disabled="!scrolls">
            <div :class="bem('grid')">
                <div :class="bem('tabs-align', { justify: justify })">
                    <div ref="tabs" :class="bem('tabs')">
                        <button
                            :class="[bem('tab-base', { selected: isItemSelected(item) }), tabClass]"
                            v-for="item in items"
                            :key="getItemKey(item)"
                            :disabled="getItemDisabled(item)"
                            @click="itemClick(item)"
                            v-bind="getTabAttrs(item)"
                        >
                            <span :ref="getTabContentRefName(item)">
                                <slot :item="item" :selected="isItemSelected(item)">
                                    {{ getItemLabel(item) }}
                                </slot>
                            </span>
                        </button>

                        <div
                            :class="[bem('selector-base'), selectorClass]"
                            :style="{
                                left: cssPx(selectorOffset),
                                width: cssPx(selectorWidth),
                            }"
                        >
                            <slot name="selector"></slot>
                        </div>
                    </div>
                </div>
            </div>
        </PxArrowScroller>
    </div>
</template>

<script>
import PxBaseItemsSelect from '../bases/PxBaseItemsSelect.vue';
import PxBaseResize from '../bases/PxBaseResize.vue';
import PxArrowScroller from './PxArrowScroller.vue';
import { getClientRect } from '../utils/utils.js';

export default {
    name: 'px-pivot',
    components: { PxArrowScroller },
    mixins: [PxBaseResize, PxBaseItemsSelect],
    props: {
        // classes that get set on the tabs and selector line
        tabClass: { type: String, default: 'px-pivot__tab' },
        selectorClass: { type: String, default: 'px-pivot__selector' },

        animateSelector: { type: Boolean, default: true },

        // a function that will return attributes that should be set on the tab buttons (takes the
        // button item as an arg)
        tabAttrsFn: { type: Function, default: null },

        // if true scrolls horizontally when no more room
        scrolls: { type: Boolean, default: true },

        // how to justify the tabs within the container (start | center | end)
        justify: { type: String, default: 'center' },

        // overwrite default
        autoSelectFirst: { type: Boolean, default: true },
    },
    data() {
        return {
            selectorVisible: false,
            selectorOffset: 0,
            selectorWidth: 0,
            animated: false,
            loading: true,
            resizing: false,
        };
    },
    computed: {
        updateMode() {
            return 'single';
        },
    },
    watch: {
        selectedKeys(nv) {
            if (nv) {
                this.updateSelector();
            }
        },
        items: {
            deep: true,
            handler() {
                this.$nextTick(() => {
                    this.updateSelector();
                });
            },
        },
    },
    mounted() {
        setTimeout(() => {
            this.updateSelector();
            setTimeout(() => {
                this.loading = false;
            }, 50);
        }, 50);
    },

    methods: {
        resize() {
            this.updateSelector();
        },
        updateSelector() {
            // don't update if 0 size
            if (this.$el?.offsetWidth === 0) {
                return;
            }

            if (!this.selectedItem) {
                return;
            }

            const refName = this.getTabContentRefName(this.selectedItem);
            const selected = this.$refs[refName]?.[0];

            // the selected tab may not be rendered yet (the items/selectedKeys
            // watchers re-run this once it is)
            if (!selected) {
                this.selectorVisible = false;
                return;
            }

            const selectedRect = getClientRect(selected, this.$refs.tabs);
            this.selectorVisible = true;
            this.selectorOffset = selectedRect.left;
            this.selectorWidth = selectedRect.width;

            if (this.scrolls && this.animated) {
                selected.scrollIntoView({
                    behavior: 'smooth',
                    inline: 'nearest',
                    block: 'nearest',
                });
            }
        },

        getTabContentRefName(item) {
            if (!item) {
                return null;
            }
            return 'tab' + this.getItemKey(item);
        },

        itemClick(item) {
            clearTimeout(this.animateTimeout);

            this.animated = this.animateSelector;

            this.$nextTick(() => {
                this.selectItemOnly(item);
            });

            this.animateTimeout = setTimeout(() => {
                this.animated = false;
            }, 1000);
        },

        getTabAttrs(item) {
            if (this.tabAttrsFn) {
                return this.tabAttrsFn(item);
            }
            return null;
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;
@use '@thinkpixellab-public/px-styles/src/modules/controls' as controls;

.px-pivot {
    // disable animation until loaded
    &--loading {
        * {
            transition: none !important;
        }
    }

    // * {
    //     transition: none !important;
    // }

    --px-pivot-tab-padding: 0.5em;
    --px-pivot-tab-offset: -0.5em;

    // &--scrolls {
    //     max-width: 100%;
    //     overflow-x: auto;
    //     -webkit-overflow-scrolling: touch;
    //     @include invisible-scrollbar();
    // }

    &__grid {
        display: grid;
        grid-template-columns: minmax(min-content, 100%);
    }

    &__tabs-align {
        min-width: 100%;
        width: auto;
        display: flex;
        position: relative;
        &--justify-center {
            justify-content: center;
        }
        &--justify-start {
            justify-content: flex-start;
            left: var(--px-pivot-tab-offset);
        }

        &--justify-end {
            justify-content: flex-end;
            right: var(--px-pivot-tab-offset);
        }
    }

    &__tabs {
        position: relative;
        display: flex;
        flex: none;
    }
    &__tab-base {
        @include controls.control-reset();
        background-color: transparent;
        flex: none;
    }

    &__tab {
        padding: var(--px-pivot-tab-padding);
        cursor: pointer;
        &:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }
    }

    &__selector-base {
        position: absolute;
        bottom: 0;
        left: 0;
    }

    &__selector {
        height: 2px;
        background-color: currentColor;
    }

    &--animated & {
        &__selector-base {
            @include transition(left width opacity, $dur: 400ms, $ease: $ease-out-quart);
        }
    }

    &--loading {
        * {
            transition: none !important;
        }
    }
}
</style>
