<!--
    Shows a simple CSS based spinner. Future implementations can pull from here:
    https://cssloaders.github.io/

    Supported variants:

        * classic - rotating semi-circle
        * dots - three dots that fade in and out in turn

    Size is derived from the current font size and color is derived from var(--px-spinner-color). These
    properties (as well as a transform) can be set on the component itself without side effects.

    Future enhancements could include additional properties for controlling things like timing,
    additional colors, stroke thickness, etc.
-->

<template>
    <span :class="bem(variantsMap)" v-if="visible">
        <span :class="bem('spinner')"></span>
    </span>
</template>

<script>
import PxBaseVariants from '../bases/PxBaseVariants.vue';
import PxBaseVisible from '../bases/PxBaseVisible.vue';

export default {
    name: 'px-spinner',
    mixins: [PxBaseVariants, PxBaseVisible],
    props: {
        /**
         * The variant of spinner to show.
         * @values classic, dots
         */
        variant: { type: String, default: 'classic' },
        duration: { type: Number, default: 2 },
    },
    computed: {
        durationSeconds() {
            return this.duration + 's';
        },
    },
};
</script>

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

.px-spinner {
    display: inline-block;
    position: relative;
    pointer-events: none;

    --px-spinner-dur: v-bind(durationSeconds);
    --px-spinner-linewidth: 0.15em;
    --px-spinner-color: currentColor;
    --px-spinner-color-secondary: transparent;

    &__spinner {
        display: block;
        position: relative;
    }

    // classic

    &--classic & {
        &__spinner {
            position: relative;
            width: 1.33em;
            height: 1.33em;
            border: var(--px-spinner-linewidth) solid var(--px-spinner-color);
            border-bottom-color: var(--px-spinner-color-secondary);
            border-radius: 50%;
            display: inline-block;
            box-sizing: border-box;
            animation: px-spinner-classic var(--px-spinner-dur) linear infinite;
        }
    }

    @keyframes px-spinner-classic {
        0% {
            transform: rotate(0deg);
        }
        100% {
            transform: rotate(360deg);
        }
    }

    // dots

    &--dots {
        width: 12.5em * 0.2;
        height: 2.5em * 0.2;
    }

    &--dots & {
        $dur: 1.8s;

        &__spinner {
            font-size: 0.2em;
        }

        &__spinner,
        &__spinner:before,
        &__spinner:after {
            position: absolute;
            top: -2em;
            width: 2em;
            height: 2em;
            border-radius: 50%;
            animation-fill-mode: both;
            animation: px-spinner-dots var(--px-spinner-dur) infinite $ease-in-out-quart;
        }
        &__spinner {
            left: 5em;
            color: var(--px-spinner-color);
            position: relative;
            text-indent: -9999em;
            transform: translateZ(0);
            animation-delay: calc((var(--px-spinner-dur) * -0.088888888));
        }
        &__spinner:before,
        &__spinner:after {
            content: '';
            position: absolute;
            top: 0;
        }
        &__spinner:before {
            left: -5em;
            animation-delay: calc((var(--px-spinner-dur) * -0.088888888 * 2));
        }
        &__spinner:after {
            left: 5em;
        }

        @keyframes px-spinner-dots {
            0%,
            80%,
            100% {
                box-shadow: 0 2.5em 0 -1.3em;
            }
            60% {
                box-shadow: 0 2.5em 0 0;
            }
        }
    }
}
</style>
