use kael::*;
use std::time::Duration;
use crate::animations::{durations, easings};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction {
Top,
Bottom,
Left,
Right,
}
#[derive(IntoElement)]
pub struct Transition {
slide_direction: Option<Direction>,
slide_distance: Pixels,
duration: Duration,
easing_fn: fn(f32) -> f32,
child: Option<AnyElement>,
animation_id: ElementId,
apply_fade: bool,
}
impl Transition {
pub fn new() -> Self {
Self {
slide_direction: None,
slide_distance: px(20.0),
duration: durations::NORMAL,
easing_fn: easings::ease_out_cubic,
child: None,
animation_id: ElementId::Name("transition".into()),
apply_fade: false,
}
}
pub fn id(mut self, id: impl Into<ElementId>) -> Self {
self.animation_id = id.into();
self
}
pub fn fade(mut self) -> Self {
self.apply_fade = true;
self
}
pub fn slide(mut self, direction: Direction) -> Self {
self.slide_direction = Some(direction);
self
}
pub fn distance(mut self, distance: Pixels) -> Self {
self.slide_distance = distance;
self
}
pub fn duration(mut self, duration: Duration) -> Self {
self.duration = duration;
self
}
pub fn smooth(mut self) -> Self {
self.easing_fn = easings::ease_out_cubic;
self
}
pub fn spring(mut self) -> Self {
self.easing_fn = easings::smooth_spring;
self
}
pub fn snappy(mut self) -> Self {
self.easing_fn = easings::ease_out_back;
self
}
pub fn linear(mut self) -> Self {
self.easing_fn = easings::linear;
self
}
pub fn child(mut self, child: impl IntoElement) -> Self {
self.child = Some(child.into_any_element());
self
}
}
impl Default for Transition {
fn default() -> Self {
Self::new()
}
}
impl RenderOnce for Transition {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let child = self.child.unwrap_or_else(|| div().into_any_element());
let easing_fn = self.easing_fn;
let animation_id = self.animation_id.clone();
let slide_direction = self.slide_direction;
let slide_distance = self.slide_distance;
let duration = self.duration;
let apply_fade = self.apply_fade;
if let Some(direction) = slide_direction {
div()
.id(animation_id.clone())
.relative()
.child(child)
.with_animation(
animation_id,
Animation::new(duration).with_easing(easing_fn),
move |el, delta| {
let offset = slide_distance * (1.0 - delta);
let positioned = match direction {
Direction::Top => el.top(-offset),
Direction::Bottom => el.top(offset),
Direction::Left => el.left(-offset),
Direction::Right => el.left(offset),
};
if apply_fade {
positioned.opacity(delta)
} else {
positioned
}
},
)
} else {
div()
.id(animation_id.clone())
.relative()
.child(child)
.with_animation(
animation_id,
Animation::new(duration).with_easing(easing_fn),
|el, delta| el.opacity(delta),
)
}
}
}
impl Transition {
pub fn fade_quick() -> Self {
Self::new().fade().duration(durations::FAST)
}
pub fn fade_normal() -> Self {
Self::new().fade().duration(durations::NORMAL)
}
pub fn fade_slow() -> Self {
Self::new().fade().duration(durations::SLOW)
}
pub fn slide_up() -> Self {
Self::new()
.slide(Direction::Bottom)
.fade()
.duration(durations::NORMAL)
}
pub fn slide_down() -> Self {
Self::new()
.slide(Direction::Top)
.fade()
.duration(durations::NORMAL)
}
pub fn slide_left() -> Self {
Self::new()
.slide(Direction::Left)
.fade()
.duration(durations::NORMAL)
}
pub fn slide_right() -> Self {
Self::new()
.slide(Direction::Right)
.fade()
.duration(durations::NORMAL)
}
pub fn slide_up_spring() -> Self {
Self::new()
.slide(Direction::Bottom)
.fade()
.spring()
.duration(durations::SLOW)
}
pub fn scale_smooth() -> Self {
Self::fade_normal().snappy()
}
pub fn scale_bounce() -> Self {
Self::fade_normal().spring().duration(durations::SLOW)
}
pub fn scale_snappy() -> Self {
Self::fade_quick().snappy()
}
}