oxihuman_export/
web_animation_api_export.rs1#![allow(dead_code)]
4
5pub struct WebAnimKeyframe {
9 pub offset: f32,
10 pub property: String,
11 pub value: String,
12 pub easing: String,
13}
14
15pub struct WebAnimOptions {
17 pub duration: u32,
18 pub iterations: f32,
19 pub fill: String,
20 pub easing: String,
21 pub delay: i32,
22}
23
24impl Default for WebAnimOptions {
25 fn default() -> Self {
26 Self {
27 duration: 1000,
28 iterations: 1.0,
29 fill: "none".to_string(),
30 easing: "ease".to_string(),
31 delay: 0,
32 }
33 }
34}
35
36pub struct WebAnimExport {
38 pub keyframes: Vec<WebAnimKeyframe>,
39 pub options: WebAnimOptions,
40 pub target_selector: String,
41}
42
43pub fn new_web_anim_export(target: &str, options: WebAnimOptions) -> WebAnimExport {
45 WebAnimExport {
46 keyframes: Vec::new(),
47 options,
48 target_selector: target.to_string(),
49 }
50}
51
52pub fn add_web_anim_keyframe(
54 exp: &mut WebAnimExport,
55 offset: f32,
56 property: &str,
57 value: &str,
58 easing: &str,
59) {
60 exp.keyframes.push(WebAnimKeyframe {
61 offset: offset.clamp(0.0, 1.0),
62 property: property.to_string(),
63 value: value.to_string(),
64 easing: easing.to_string(),
65 });
66}
67
68pub fn web_anim_keyframe_count(exp: &WebAnimExport) -> usize {
70 exp.keyframes.len()
71}
72
73pub fn render_web_anim_json(exp: &WebAnimExport) -> String {
75 format!(
76 r#"{{"target":"{}","duration":{},"keyframes":{}}}"#,
77 exp.target_selector,
78 exp.options.duration,
79 exp.keyframes.len()
80 )
81}
82
83pub fn validate_web_anim(exp: &WebAnimExport) -> bool {
85 !exp.target_selector.is_empty() && exp.options.duration > 0
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn new_export_empty() {
94 let exp = new_web_anim_export("#el", WebAnimOptions::default());
95 assert_eq!(web_anim_keyframe_count(&exp), 0 );
96 }
97
98 #[test]
99 fn add_keyframe_increments() {
100 let mut exp = new_web_anim_export("#el", WebAnimOptions::default());
101 add_web_anim_keyframe(&mut exp, 0.0, "opacity", "0", "ease");
102 assert_eq!(web_anim_keyframe_count(&exp), 1 );
103 }
104
105 #[test]
106 fn offset_clamped() {
107 let mut exp = new_web_anim_export("#el", WebAnimOptions::default());
108 add_web_anim_keyframe(&mut exp, 1.5, "x", "10px", "ease");
109 assert!(exp.keyframes[0].offset <= 1.0 );
110 }
111
112 #[test]
113 fn validate_valid() {
114 let exp = new_web_anim_export("#div", WebAnimOptions::default());
115 assert!(validate_web_anim(&exp) );
116 }
117
118 #[test]
119 fn validate_empty_target_fails() {
120 let exp = new_web_anim_export("", WebAnimOptions::default());
121 assert!(!validate_web_anim(&exp) );
122 }
123
124 #[test]
125 fn render_contains_target() {
126 let exp = new_web_anim_export("#my-el", WebAnimOptions::default());
127 let json = render_web_anim_json(&exp);
128 assert!(json.contains("my-el") );
129 }
130
131 #[test]
132 fn render_contains_duration() {
133 let opt = WebAnimOptions {
134 duration: 2500,
135 ..Default::default()
136 };
137 let exp = new_web_anim_export("#x", opt);
138 let json = render_web_anim_json(&exp);
139 assert!(json.contains("2500") );
140 }
141
142 #[test]
143 fn default_options_reasonable() {
144 let opt = WebAnimOptions::default();
145 assert!(opt.duration > 0 );
146 assert!(opt.iterations >= 1.0 );
147 }
148
149 #[test]
150 fn multiple_keyframes() {
151 let mut exp = new_web_anim_export("#a", WebAnimOptions::default());
152 add_web_anim_keyframe(&mut exp, 0.0, "opacity", "0", "ease");
153 add_web_anim_keyframe(&mut exp, 0.5, "opacity", "0.5", "linear");
154 add_web_anim_keyframe(&mut exp, 1.0, "opacity", "1", "ease");
155 assert_eq!(web_anim_keyframe_count(&exp), 3 );
156 }
157}