freya_components/
overflowed_content.rs1use std::time::Duration;
2
3use dioxus::prelude::*;
4use freya_elements as dioxus_elements;
5use freya_hooks::{
6 use_animation,
7 use_node_signal,
8 AnimDirection,
9 AnimNum,
10 Ease,
11 Function,
12 OnFinish,
13};
14
15#[component]
41pub fn OverflowedContent(
42 children: Element,
43 #[props(default = "100%".to_string())] width: String,
44 #[props(default = "auto".to_string())] height: String,
45 #[props(default = Duration::from_secs(4))] duration: Duration,
46) -> Element {
47 let (label_reference, label_size) = use_node_signal();
48 let (rect_reference, rect_size) = use_node_signal();
49
50 let rect_width = rect_size.read().area.width();
51 let label_width = label_size.read().area.width();
52 let does_overflow = label_width > rect_width;
53
54 let animation = use_animation(move |conf| {
55 conf.on_finish(OnFinish::Restart);
56
57 AnimNum::new(0., 100.)
58 .duration(duration)
59 .ease(Ease::InOut)
60 .function(Function::Linear)
61 });
62
63 use_effect(use_reactive!(|does_overflow| {
64 if does_overflow {
65 animation.run(AnimDirection::Forward);
66 }
67 }));
68
69 let progress = animation.get().read().read();
70 let offset_x = if does_overflow {
71 ((label_width + rect_width) * progress / 100.) - rect_width
72 } else {
73 0.
74 };
75
76 rsx!(
77 rect {
78 width,
79 height,
80 offset_x: "{-offset_x}",
81 overflow: "clip",
82 reference: rect_reference,
83 rect {
84 reference: label_reference,
85 max_lines: "1",
86 {children}
87 }
88 }
89 )
90}
91
92#[cfg(test)]
93mod test {
94 use std::time::Duration;
95
96 use freya::prelude::*;
97 use freya_testing::prelude::*;
98 use tokio::time::sleep;
99
100 #[tokio::test]
101 pub async fn overflowed_content() {
102 fn app() -> Element {
103 rsx!(
104 OverflowedContent {
105 duration: Duration::from_millis(50),
106 width: "50",
107 label {
108 "123456789123456789"
109 }
110 }
111 )
112 }
113
114 let mut utils = launch_test(app);
115
116 utils.config().event_loop_ticker = false;
118
119 let root = utils.root();
120 let label = root.get(0).get(0).get(0);
121
122 utils.wait_for_update().await;
123 utils.wait_for_update().await;
124 utils.wait_for_update().await;
125 assert_eq!(label.layout().unwrap().area.min_x(), 50.);
126
127 sleep(Duration::from_millis(5)).await;
128 utils.wait_for_update().await;
129 utils.wait_for_update().await;
130 assert_ne!(label.layout().unwrap().area.min_x(), 50.);
131 }
132}