dioxus-motion 0.3.5

Animations library for Dioxus.
Documentation
use crate::Duration;
use crate::animations::core::Animatable;
use tracing::error;

pub type EasingFn = fn(f32, f32, f32, f32) -> f32;

#[derive(Debug, thiserror::Error)]
pub enum KeyframeError {
    #[error("Failed to compare keyframe offsets (possible NaN value)")]
    InvalidOffset,
}

#[derive(Clone)]
pub struct Keyframe<T: Animatable> {
    pub value: T,
    pub offset: f32,
    pub easing: Option<EasingFn>,
}

#[derive(Clone)]
pub struct KeyframeAnimation<T: Animatable> {
    pub keyframes: Vec<Keyframe<T>>,
    pub duration: Duration,
}

impl<T: Animatable> KeyframeAnimation<T> {
    pub fn new(duration: Duration) -> Self {
        Self {
            keyframes: Vec::new(),
            duration,
        }
    }

    pub fn add_keyframe(
        mut self,
        value: T,
        offset: f32,
        easing: Option<EasingFn>,
    ) -> Result<Self, KeyframeError> {
        self.keyframes.push(Keyframe {
            value,
            offset: offset.clamp(0.0, 1.0),
            easing,
        });
        self.keyframes.sort_by(|a, b| {
            a.offset.partial_cmp(&b.offset).unwrap_or_else(|| {
                error!(
                    "Failed to compare keyframe offsets: {} vs {}",
                    a.offset, b.offset
                );
                std::cmp::Ordering::Equal
            })
        });
        if self.keyframes.iter().any(|k| k.offset.is_nan()) {
            error!("Keyframe sorting failed: InvalidOffset (NaN offset)");
            return Err(KeyframeError::InvalidOffset);
        }
        Ok(self)
    }
}