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
use std::time::Duration;

use dioxus::prelude::*;
use freya_elements::elements as dioxus_elements;
use freya_hooks::{
    use_animation_with_dependencies,
    use_node_signal_with_prev,
    AnimDirection,
    AnimNum,
    Ease,
    Function,
};

#[component]
pub fn AnimatedPosition(
    children: Element,
    width: String,
    height: String,
    #[props(default = Function::default())] function: Function,
    #[props(default = Duration::from_millis(250))] duration: Duration,
    #[props(default = Ease::default())] ease: Ease,
) -> Element {
    let mut render_element = use_signal(|| false);
    let (reference, size, old_size) = use_node_signal_with_prev();

    let animations = use_animation_with_dependencies(
        &(function, duration, ease),
        move |ctx, (function, duration, ease)| {
            let old_size = old_size().unwrap_or_default();
            let size = size().unwrap_or_default();
            (
                ctx.with(
                    AnimNum::new(size.area.origin.x, old_size.area.origin.x)
                        .duration(duration)
                        .ease(ease)
                        .function(function),
                ),
                ctx.with(
                    AnimNum::new(size.area.origin.y, old_size.area.origin.y)
                        .duration(duration)
                        .ease(ease)
                        .function(function),
                ),
            )
        },
    );

    use_effect(move || {
        if animations.is_running() {
            render_element.set(true);
        }
    });

    use_effect(move || {
        let has_size = size.read().is_some();
        let has_old_size = old_size.read().is_some();
        if has_size && has_old_size {
            animations.run(AnimDirection::Reverse);
        } else if has_size {
            render_element.set(true);
        }
    });

    let (offset_x, offset_y) = animations.get();
    let offset_x = offset_x.read().as_f32();
    let offset_y = offset_y.read().as_f32();

    rsx!(
        rect {
            reference,
            width: "{width}",
            height: "{height}",
            rect {
                width: "0",
                height: "0",
                offset_x: "{offset_x}",
                offset_y: "{offset_y}",
                position: "fixed",
                if render_element() {
                    rect {
                        width: "{size.read().as_ref().unwrap().area.width()}",
                        height: "{size.read().as_ref().unwrap().area.height()}",
                        {children}
                    }
                }
            }
        }
    )
}