encre_css/plugins/transition/animation/
mod.rs

1#![doc = include_str!("README.md")]
2#![doc(alias = "transition")]
3use crate::prelude::build_plugin::*;
4
5const SPIN_ANIMATION: &str = "@-webkit-keyframes spin {
6  to {
7    transform: rotate(360deg);
8  }
9}
10
11@keyframes spin {
12  from {
13    transform: rotate(0deg);
14  }
15  to {
16    transform: rotate(360deg);
17  }
18}\n\n";
19
20const PING_ANIMATION: &str = "@-webkit-keyframes ping {
21  75%, 100% {
22    transform: scale(2);
23    opacity: 0;
24  }
25}
26
27@keyframes ping {
28  75%, 100% {
29    transform: scale(2);
30    opacity: 0;
31  }
32}\n\n";
33
34const PULSE_ANIMATION: &str = "@-webkit-keyframes pulse {
35  50% {
36    opacity: .5;
37  }
38}
39
40@keyframes pulse {
41  0%, 100% {
42    opacity: 1;
43  }
44  50% {
45    opacity: .5;
46  }
47}\n\n";
48
49const BOUNCE_ANIMATION: &str = "@-webkit-keyframes bounce {
50  0%, 100% {
51    transform: translateY(-25%);
52    -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);
53    animation-timing-function: cubic-bezier(0.8,0,1,1);
54  }
55
56  50% {
57    transform: none;
58    -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);
59    animation-timing-function: cubic-bezier(0,0,0.2,1);
60  }
61}
62
63@keyframes bounce {
64  0%, 100% {
65    transform: translateY(-25%);
66    -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);
67    animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
68  }
69  50% {
70    transform: translateY(0);
71    -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);
72    animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
73  }
74}\n\n";
75
76#[derive(Debug)]
77pub(crate) struct PluginDefinition;
78
79impl Plugin for PluginDefinition {
80    fn needs_wrapping(&self) -> bool {
81        false
82    }
83
84    fn can_handle(&self, context: ContextCanHandle) -> bool {
85        match context.modifier {
86            Modifier::Builtin { value, .. } => {
87                ["spin", "ping", "pulse", "bounce", "none"].contains(value)
88            }
89            Modifier::Arbitrary { value, .. } => is_matching_all(value),
90        }
91    }
92
93    fn handle(&self, context: &mut ContextHandle) {
94        match context.modifier {
95            Modifier::Builtin { value, .. } => {
96                let animation = match *value {
97                    "none" => "none",
98                    "spin" => {
99                        context.buffer.raw(SPIN_ANIMATION);
100                        "spin 1s linear infinite"
101                    }
102                    "ping" => {
103                        context.buffer.raw(PING_ANIMATION);
104                        "ping 1s cubic-bezier(0, 0, 0.2, 1) infinite"
105                    }
106                    "pulse" => {
107                        context.buffer.raw(PULSE_ANIMATION);
108                        "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
109                    }
110                    "bounce" => {
111                        context.buffer.raw(BOUNCE_ANIMATION);
112                        "bounce 1s infinite"
113                    }
114                    _ => unreachable!(),
115                };
116
117                generate_wrapper(context, |context| {
118                    context.buffer.lines([
119                        format_args!("-webkit-animation: {animation};"),
120                        format_args!("animation: {animation};"),
121                    ]);
122                });
123            }
124            Modifier::Arbitrary { value, .. } => generate_wrapper(context, |context| {
125                context.buffer.lines([
126                    format_args!("-webkit-animation: {value};"),
127                    format_args!("animation: {value};"),
128                ]);
129            }),
130        }
131    }
132}