All files / src/components/Spinner/variants Pulse.vue

100% Statements 9/9
100% Branches 8/8
100% Functions 3/3
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                  24x           24x 24x         24x   24x       24x     24x                   23x                                                                                                                                
<script setup lang="ts">
import { computed } from "vue";
 
interface Props {
  size?: string | number;
  color?: string;
  speed?: number;
}
 
const props = withDefaults(defineProps<Props>(), {
  size: 40,
  color: "currentColor",
  speed: 1,
});
 
const formattedSize = computed(() => {
  return typeof props.size === "number"
    ? `${props.size}px`
    : props.size;
});
 
const formattedDuration = computed(() => {
  const safeSpeed =
    Number.isFinite(props.speed) && props.speed > 0
      ? props.speed
      : 1;
 
  return `${1 / safeSpeed}s`;
});
 
const pulseStyle = computed(() => ({
  width: formattedSize.value,
  height: formattedSize.value,
  color: props.color,
  "--vslk-pulse-color": props.color,
  "--vslk-pulse-duration": formattedDuration.value,
}));
</script>
 
<template>
  <div class="vslk-spinner-pulse" :style="pulseStyle">
    <span class="vslk-spinner-pulse__wave" />
    <span class="vslk-spinner-pulse__core" />
  </div>
</template>
 
<style scoped>
.vslk-spinner-pulse {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  flex-shrink: 0;
}
 
.vslk-spinner-pulse__core {
  position: absolute;
  width: 38%;
  height: 38%;
  border-radius: 50%;
  background-color: var(--vslk-pulse-color);
  animation: vslk-pulse-core var(--vslk-pulse-duration)
    ease-in-out infinite;
}
 
.vslk-spinner-pulse__wave {
  position: absolute;
  width: 38%;
  height: 38%;
  box-sizing: border-box;
  border: 2px solid var(--vslk-pulse-color);
  border-radius: 50%;
  animation: vslk-pulse-wave var(--vslk-pulse-duration)
    ease-out infinite;
}
 
@keyframes vslk-pulse-core {
  0%,
  100% {
    transform: scale(0.85);
    opacity: 0.7;
  }
 
  50% {
    transform: scale(1.15);
    opacity: 1;
  }
}
 
@keyframes vslk-pulse-wave {
  0% {
    transform: scale(0.7);
    opacity: 0.9;
  }
 
  70%,
  100% {
    transform: scale(2.5);
    opacity: 0;
  }
}
</style>