Skip to main content

cranpose_animation/
unit_animation.rs

1//! Animation over Cranpose's density/scale unit types.
2//!
3//! Layers [`Lerp`] and [`SpringScalar`] onto [`Dp`] and [`Sp`] so they plug
4//! into the same generic [`animateValueAsState`] core that
5//! [`animateFloatAsState`](crate::animateFloatAsState) and
6//! [`animateColorAsState`](crate::animateColorAsState) already use.
7//!
8//! Note: This module uses camelCase for function names to maintain 1:1 API
9//! parity with Jetpack Compose.
10
11#![expect(non_snake_case, reason = "names follow Compose's casing")]
12
13use cranpose_core::State;
14use cranpose_ui_graphics::{Dp, Sp};
15
16use crate::animation::{AnimationType, Lerp, SpringScalar, animateValueAsState};
17
18macro_rules! impl_length_animation {
19    ($($unit:ty),*) => {$(
20        impl Lerp for $unit {
21            fn lerp(&self, target: &Self, fraction: f32) -> Self {
22                Self(self.0.lerp(&target.0, fraction))
23            }
24        }
25
26        impl SpringScalar for $unit {
27            const DIMENSIONS: usize = 1;
28
29            fn dimension(&self, _index: usize) -> f32 {
30                self.0
31            }
32
33            fn from_dimensions(dimensions: [f32; crate::animation::SPRING_MAX_DIMENSIONS]) -> Self {
34                Self(dimensions[0])
35            }
36        }
37    )*};
38}
39
40impl_length_animation!(Dp, Sp);
41
42/// Fire-and-forget animation of a density-independent length.
43///
44/// Mirrors Jetpack Compose: `animateDpAsState(targetValue, animationSpec, label)`.
45#[track_caller]
46pub fn animateDpAsState(target: Dp, animation: AnimationType, label: &str) -> State<Dp> {
47    animateValueAsState(target, animation, label)
48}
49
50#[cfg(test)]
51#[path = "tests/unit_animation_tests.rs"]
52mod tests;