import { computed, defineComponent, h, onBeforeUnmount, ref, watch } from 'vue' import { useLoading } from '@/store/state.js' export default defineComponent({ props: { throttle: { type: Number, default: 50, }, duration: { type: Number, default: 500, }, height: { type: Number, default: 3, }, color: { type: [String, Boolean], default: 'repeating-linear-gradient(to right, var(--color-brand) 0%, var(--color-brand) 100%)', }, offsetWidth: { type: String, default: '208px', }, offsetHeight: { type: String, default: '52px', }, }, setup(props, { slots }) { const indicator = useLoadingIndicator({ duration: props.duration, throttle: props.throttle, }) onBeforeUnmount(() => indicator.clear) const loading = useLoading() watch(loading, (newValue) => { if (newValue.barEnabled) { if (newValue.loading) { indicator.start() } else { indicator.finish() } } }) return () => h( 'div', { style: { position: 'fixed', top: props.offsetHeight, right: 0, left: props.offsetWidth, pointerEvents: 'none', width: `calc((100vw - ${props.offsetWidth}) * ${indicator.progress.value / 100})`, height: `${props.height}px`, opacity: indicator.isLoading.value ? 1 : 0, background: props.color || undefined, backgroundSize: `${(100 / indicator.progress.value) * 100}% auto`, transition: 'width 0.1s, height 0.4s, opacity 0.4s', zIndex: 6, }, }, slots, ) }, }) function useLoadingIndicator(opts) { const progress = ref(0) const isLoading = ref(false) const step = computed(() => 10000 / opts.duration) let _timer = null let _throttle = null function start() { clear() progress.value = 0 if (opts.throttle) { _throttle = setTimeout(() => { isLoading.value = true _startTimer() }, opts.throttle) } else { isLoading.value = true _startTimer() } } function finish() { progress.value = 100 _hide() } function clear() { clearInterval(_timer) clearTimeout(_throttle) _timer = null _throttle = null } function _increase(num) { progress.value = Math.min(100, progress.value + num) } function _hide() { clear() setTimeout(() => { isLoading.value = false setTimeout(() => { progress.value = 0 }, 400) }, 500) } function _startTimer() { _timer = setInterval(() => { _increase(step.value) }, 100) } return { progress, isLoading, start, finish, clear, } }