#![allow(dead_code)]
pub struct WebAnimKeyframe {
pub offset: f32,
pub property: String,
pub value: String,
pub easing: String,
}
pub struct WebAnimOptions {
pub duration: u32,
pub iterations: f32,
pub fill: String,
pub easing: String,
pub delay: i32,
}
impl Default for WebAnimOptions {
fn default() -> Self {
Self {
duration: 1000,
iterations: 1.0,
fill: "none".to_string(),
easing: "ease".to_string(),
delay: 0,
}
}
}
pub struct WebAnimExport {
pub keyframes: Vec<WebAnimKeyframe>,
pub options: WebAnimOptions,
pub target_selector: String,
}
pub fn new_web_anim_export(target: &str, options: WebAnimOptions) -> WebAnimExport {
WebAnimExport {
keyframes: Vec::new(),
options,
target_selector: target.to_string(),
}
}
pub fn add_web_anim_keyframe(
exp: &mut WebAnimExport,
offset: f32,
property: &str,
value: &str,
easing: &str,
) {
exp.keyframes.push(WebAnimKeyframe {
offset: offset.clamp(0.0, 1.0),
property: property.to_string(),
value: value.to_string(),
easing: easing.to_string(),
});
}
pub fn web_anim_keyframe_count(exp: &WebAnimExport) -> usize {
exp.keyframes.len()
}
pub fn render_web_anim_json(exp: &WebAnimExport) -> String {
format!(
r#"{{"target":"{}","duration":{},"keyframes":{}}}"#,
exp.target_selector,
exp.options.duration,
exp.keyframes.len()
)
}
pub fn validate_web_anim(exp: &WebAnimExport) -> bool {
!exp.target_selector.is_empty() && exp.options.duration > 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_export_empty() {
let exp = new_web_anim_export("#el", WebAnimOptions::default());
assert_eq!(web_anim_keyframe_count(&exp), 0 );
}
#[test]
fn add_keyframe_increments() {
let mut exp = new_web_anim_export("#el", WebAnimOptions::default());
add_web_anim_keyframe(&mut exp, 0.0, "opacity", "0", "ease");
assert_eq!(web_anim_keyframe_count(&exp), 1 );
}
#[test]
fn offset_clamped() {
let mut exp = new_web_anim_export("#el", WebAnimOptions::default());
add_web_anim_keyframe(&mut exp, 1.5, "x", "10px", "ease");
assert!(exp.keyframes[0].offset <= 1.0 );
}
#[test]
fn validate_valid() {
let exp = new_web_anim_export("#div", WebAnimOptions::default());
assert!(validate_web_anim(&exp) );
}
#[test]
fn validate_empty_target_fails() {
let exp = new_web_anim_export("", WebAnimOptions::default());
assert!(!validate_web_anim(&exp) );
}
#[test]
fn render_contains_target() {
let exp = new_web_anim_export("#my-el", WebAnimOptions::default());
let json = render_web_anim_json(&exp);
assert!(json.contains("my-el") );
}
#[test]
fn render_contains_duration() {
let opt = WebAnimOptions {
duration: 2500,
..Default::default()
};
let exp = new_web_anim_export("#x", opt);
let json = render_web_anim_json(&exp);
assert!(json.contains("2500") );
}
#[test]
fn default_options_reasonable() {
let opt = WebAnimOptions::default();
assert!(opt.duration > 0 );
assert!(opt.iterations >= 1.0 );
}
#[test]
fn multiple_keyframes() {
let mut exp = new_web_anim_export("#a", WebAnimOptions::default());
add_web_anim_keyframe(&mut exp, 0.0, "opacity", "0", "ease");
add_web_anim_keyframe(&mut exp, 0.5, "opacity", "0.5", "linear");
add_web_anim_keyframe(&mut exp, 1.0, "opacity", "1", "ease");
assert_eq!(web_anim_keyframe_count(&exp), 3 );
}
}