Skip to content

Commit 09fcb0e

Browse files
committed
feat: 增加animation、keyframe的解析
1 parent 30dcdeb commit 09fcb0e

File tree

7 files changed

+235
-10
lines changed

7 files changed

+235
-10
lines changed

__test__/fixure/normal.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ const Index = () => {
66
)
77
};
88

9+
10+
911
export default Index;

__test__/fixure/pesudo.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
}
44

55
@keyframes fade {
6-
0% {
6+
0%, 10% {
77
opacity: 0;
88
}
99
100% {
1010
opacity: 1;
11+
width: 30px;
1112
}
1213
}

src/parse_style_properties.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use std::{cell::RefCell, collections::HashMap, rc::Rc};
2+
13
use lightningcss::{properties::Property, stylesheet::PrinterOptions};
24

3-
use crate::style_propetries::{aspect_ratio::AspactRatio, background::Background, background_image::BackgroundImage, background_position::BackgroundPosition, background_repeat::BackgroundRepeat, background_size::BackgroundSize, border::Border, border_color::BorderColor, border_radius::BorderRadius, border_style::BorderStyle, border_width::BorderWidth, color::ColorProperty, display::Display, flex::Flex, flex_align::FlexAlign, flex_basis::FlexBasis, flex_direction::FlexDirection, flex_wrap::FlexWrap, font_size::FontSize, font_style::FontStyle, font_weight::FontWeight, gap::Gap, item_align::ItemAlign, length_value::LengthValueProperty, letter_spacing::LetterSpacing, line_height::LineHeight, marin_padding::MarginPadding, max_size::MaxSizeProperty, normal::Normal, number::NumberProperty, overflow::Overflow, size::SizeProperty, style_value_type::StyleValueType, text_align::TextAlign, text_decoration::TextDecoration, text_overflow::TextOverflow, text_shadow::TextShadow, text_transform::TextTransform, transform::Transform, transform_origin::TransformOrigin, vertical_align::VerticalAlign};
5+
use crate::{style_parser::KeyFrameItem, style_propetries::{animation::Animation, aspect_ratio::AspactRatio, background::Background, background_image::BackgroundImage, background_position::BackgroundPosition, background_repeat::BackgroundRepeat, background_size::BackgroundSize, border::Border, border_color::BorderColor, border_radius::BorderRadius, border_style::BorderStyle, border_width::BorderWidth, color::ColorProperty, display::Display, flex::Flex, flex_align::FlexAlign, flex_basis::FlexBasis, flex_direction::FlexDirection, flex_wrap::FlexWrap, font_size::FontSize, font_style::FontStyle, font_weight::FontWeight, gap::Gap, item_align::ItemAlign, length_value::LengthValueProperty, letter_spacing::LetterSpacing, line_height::LineHeight, marin_padding::MarginPadding, max_size::MaxSizeProperty, normal::Normal, number::NumberProperty, overflow::Overflow, size::SizeProperty, style_value_type::StyleValueType, text_align::TextAlign, text_decoration::TextDecoration, text_overflow::TextOverflow, text_shadow::TextShadow, text_transform::TextTransform, transform::Transform, transform_origin::TransformOrigin, vertical_align::VerticalAlign}};
46

5-
pub fn parse_style_properties(properties: &Vec<(String, Property)>) -> Vec<StyleValueType> {
7+
pub fn parse_style_properties(properties: &Vec<(String, Property)>, keyframes_map: Option<Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>>) -> Vec<StyleValueType> {
68
let mut final_properties = vec![];
79
for (id, value) in properties.iter() {
810
let property_name = id.as_str();
@@ -172,6 +174,11 @@ pub fn parse_style_properties(properties: &Vec<(String, Property)>) -> Vec<Style
172174
final_properties.push(StyleValueType::Normal(Normal::new(id.to_string(), content_value.to_string())));
173175
}
174176
}
177+
"animation" => {
178+
if let Some(ref keyframes_map) = keyframes_map {
179+
final_properties.push(StyleValueType::Animation(Animation::from((id.to_string(), value, keyframes_map.clone()))))
180+
}
181+
}
175182
_ => {
176183
// position、zIndex等... 会自动处理 单位、数字等相关信息
177184
final_properties.push(StyleValueType::Normal(Normal::new(id.to_string(), value.value_to_css_string(PrinterOptions::default()).unwrap())));

src/style_parser.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{rc::Rc, cell::RefCell, convert::Infallible, collections::HashMap, hash::Hash};
22

3-
use lightningcss::{stylesheet::{StyleSheet, ParserOptions, PrinterOptions}, visitor::{Visit, Visitor, VisitTypes}, visit_types, rules::CssRule, properties::Property, declaration::DeclarationBlock, traits::ToCss};
3+
use lightningcss::{declaration::DeclarationBlock, properties::Property, rules::{keyframes::KeyframeSelector, CssRule}, stylesheet::{ParserOptions, PrinterOptions, StyleSheet}, traits::ToCss, visit_types, visitor::{Visit, VisitTypes, Visitor}};
44

55
use crate::{constants::SUPPORT_PSEUDO_KEYS, document::JSXDocument, style_propetries::{style_value_type::StyleValueType, unit::Platform}, utils::to_camel_case, visitor::SpanKey};
66

@@ -14,6 +14,16 @@ pub struct StyleData<'i> {
1414
pub has_nesting: bool
1515
}
1616

17+
pub struct KeyFramesData {
18+
pub name: String,
19+
pub keyframes: Vec<KeyFrameItem>
20+
}
21+
22+
#[derive(Debug)]
23+
pub struct KeyFrameItem {
24+
pub percentage: f32,
25+
pub declarations: Vec<StyleValueType>
26+
}
1727

1828
#[derive(Debug, Clone)]
1929
pub struct StyleDeclaration<'i> {
@@ -23,14 +33,17 @@ pub struct StyleDeclaration<'i> {
2333

2434
struct StyleVisitor<'i> {
2535
all_style: Rc<RefCell<Vec<(String, Vec<StyleDeclaration<'i>>)>>>,
36+
keyframes: Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>,
2637
}
2738

2839
impl<'i> StyleVisitor<'i> {
2940
pub fn new(
3041
all_style: Rc<RefCell<Vec<(String, Vec<StyleDeclaration<'i>>)>>>,
42+
keyframes: Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>,
3143
) -> Self {
3244
StyleVisitor {
33-
all_style
45+
all_style,
46+
keyframes
3447
}
3548
}
3649
}
@@ -39,8 +52,10 @@ impl<'i> StyleVisitor<'i> {
3952
impl<'i> Visitor<'i> for StyleVisitor<'i> {
4053
type Error = Infallible;
4154
const TYPES: VisitTypes = visit_types!(RULES);
55+
4256
fn visit_rule(&mut self, rule: &mut CssRule<'i>) -> Result<(), Self::Error> {
4357
match rule {
58+
// 属性规则收集
4459
CssRule::Style(style) => {
4560
let selectors_str = style.selectors.to_string();
4661
let selectors: Vec<&str> = selectors_str.split(",").collect::<Vec<&str>>();
@@ -64,6 +79,47 @@ impl<'i> Visitor<'i> for StyleVisitor<'i> {
6479
}
6580
}
6681
}
82+
// 动画收集
83+
CssRule::Keyframes(keyframes_rule) => {
84+
let mut keyframe_data = KeyFramesData {
85+
name: keyframes_rule.name.to_css_string(PrinterOptions::default()).unwrap(),
86+
keyframes: vec![]
87+
};
88+
keyframes_rule.keyframes.clone().into_iter().for_each(|keyframe| {
89+
keyframe.selectors.into_iter().for_each(|selector| {
90+
let properties = keyframe.declarations.iter().map(|property| {
91+
(
92+
to_camel_case(
93+
property.0
94+
.property_id()
95+
.to_css_string(PrinterOptions::default())
96+
.unwrap()
97+
.as_str(),
98+
false,
99+
),
100+
property.0.clone(),
101+
)
102+
})
103+
.collect::<Vec<(_, _)>>(); // Speci
104+
let keyframe_item = KeyFrameItem {
105+
percentage: match selector {
106+
KeyframeSelector::Percentage(percentage) => {
107+
percentage.0
108+
}
109+
KeyframeSelector::From => 0.0,
110+
KeyframeSelector::To => 100.0,
111+
},
112+
declarations: parse_style_properties(&properties, None)
113+
};
114+
115+
keyframe_data.keyframes.push(keyframe_item)
116+
117+
});
118+
});
119+
120+
let mut keyframes = self.keyframes.borrow_mut();
121+
keyframes.insert(keyframe_data.name, keyframe_data.keyframes);
122+
}
67123
_ => {}
68124
}
69125
Ok(())
@@ -72,6 +128,7 @@ impl<'i> Visitor<'i> for StyleVisitor<'i> {
72128

73129
pub struct StyleParser<'i> {
74130
pub all_style: Rc<RefCell<Vec<(String, Vec<StyleDeclaration<'i>>)>>>,
131+
pub keyframes: Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>,
75132
pub document: &'i JSXDocument,
76133
pub platform: Platform
77134
}
@@ -80,14 +137,15 @@ impl<'i> StyleParser<'i> {
80137
pub fn new(document: &'i JSXDocument, platform:Platform) -> Self {
81138
StyleParser {
82139
all_style: Rc::new(RefCell::new(vec![])),
140+
keyframes: Rc::new(RefCell::new(HashMap::new())),
83141
document,
84142
platform
85143
}
86144
}
87145

88146
pub fn parse(&mut self, css: &'i str) {
89147
let mut stylesheet = StyleSheet::parse(css, ParserOptions::default()).expect("解析样式失败");
90-
let mut style_visitor = StyleVisitor::new(Rc::clone(&self.all_style));
148+
let mut style_visitor = StyleVisitor::new(Rc::clone(&self.all_style), Rc::clone(&self.keyframes));
91149
stylesheet.visit(&mut style_visitor).unwrap();
92150
}
93151

@@ -174,7 +232,8 @@ impl<'i> StyleParser<'i> {
174232
&properties
175233
.iter()
176234
.map(|(k, v)| (k.to_owned(), v.clone()))
177-
.collect::<Vec<_>>()
235+
.collect::<Vec<_>>(),
236+
Some(self.keyframes.clone())
178237
),
179238
)
180239
})

src/style_propetries/animation.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
3+
use std::{cell::RefCell, collections::HashMap, rc::Rc};
4+
5+
use lightningcss::{printer::PrinterOptions, properties::{animation, Property}, traits::ToCss, values::time};
6+
7+
use crate::{generate_expr_lit_num, generate_invalid_expr, style_parser::KeyFrameItem, visitor::parse_style_values};
8+
use swc_core::{common::DUMMY_SP, ecma::ast::*};
9+
use super::{traits::ToExpr, unit::{Platform, PropertyTuple}};
10+
11+
#[derive(Debug, Clone)]
12+
pub struct Animation {
13+
pub id: String,
14+
pub keyframs: Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>,
15+
pub animation_name: Option<String>,
16+
pub animation_duration: f32,
17+
pub animation_delay: f32,
18+
pub animation_iteration: f32
19+
// pub value: Option<Vec<KeyFrameItem>>
20+
}
21+
22+
impl From<(String, &Property<'_>, Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>)> for Animation {
23+
fn from(value: (String, &Property<'_>, Rc<RefCell<HashMap<String, Vec<KeyFrameItem>>>>)) -> Self {
24+
25+
26+
let mut animation_name = None;
27+
let mut animation_duration: f32 = 0.0;
28+
let mut animation_delay: f32 = 0.0;
29+
let mut animation_iteration: f32 = 1.0;
30+
31+
match value.1 {
32+
// Property::AnimationName(_, _) => todo!(),
33+
// Property::AnimationDuration(_, _) => todo!(),
34+
// Property::AnimationTimingFunction(_, _) => todo!(),
35+
// Property::AnimationIterationCount(_, _) => todo!(),
36+
// Property::AnimationDirection(_, _) => todo!(),
37+
// Property::AnimationPlayState(_, _) => todo!(),
38+
// Property::AnimationDelay(_, _) => todo!(),
39+
// Property::AnimationFillMode(_, _) => todo!(),
40+
Property::Animation(animation_list, _) => {
41+
animation_list.into_iter().for_each(|animation| {
42+
animation_name = Some(animation.name.to_css_string(PrinterOptions::default()).unwrap());
43+
animation_duration = match animation.duration {
44+
time::Time::Seconds(s) => s,
45+
time::Time::Milliseconds(m) => m * 60.0,
46+
};
47+
animation_delay = match animation.delay {
48+
time::Time::Seconds(s) => s,
49+
time::Time::Milliseconds(m) => m * 60.0,
50+
};
51+
animation_iteration = match animation.iteration_count {
52+
animation::AnimationIterationCount::Number(num) => num,
53+
animation::AnimationIterationCount::Infinite => -1.0,
54+
}
55+
});
56+
},
57+
_ => {}
58+
}
59+
60+
Animation {
61+
id: value.0,
62+
keyframs: value.2.clone(),
63+
animation_name,
64+
animation_duration,
65+
animation_delay,
66+
animation_iteration
67+
}
68+
69+
}
70+
}
71+
72+
73+
impl ToExpr for Animation {
74+
fn to_expr(&self) -> PropertyTuple {
75+
if let Some(name) = &self.animation_name {
76+
let keyframe_map = self.keyframs.borrow();
77+
if let Some(keyframe_items) = keyframe_map.get(name) {
78+
79+
80+
81+
return PropertyTuple::One(
82+
"animation".to_string(),
83+
Expr::Object(ObjectLit {
84+
span: DUMMY_SP,
85+
props: vec![
86+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
87+
key: PropName::Str("params".into()),
88+
value: Box::new(Expr::Object(ObjectLit {
89+
span: DUMMY_SP,
90+
props: vec![
91+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
92+
key: PropName::Str("delay".into()),
93+
value: Box::new(generate_expr_lit_num!((self.animation_delay * 1000.0) as f64))
94+
}))),
95+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
96+
key: PropName::Str("iterations".into()),
97+
value: Box::new(generate_expr_lit_num!(self.animation_iteration as f64))
98+
}))),
99+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
100+
key: PropName::Str("duration".into()),
101+
value: Box::new(generate_expr_lit_num!((self.animation_duration * 1000.0) as f64))
102+
}))),
103+
]
104+
}))
105+
}))),
106+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
107+
key: PropName::Str("keyframes".into()),
108+
value: Box::new(Expr::Array(ArrayLit {
109+
span: DUMMY_SP,
110+
elems: keyframe_items.into_iter().map(|item| {
111+
Some(ExprOrSpread {
112+
spread: None,
113+
expr: Box::new(Expr::Object(ObjectLit {
114+
span: DUMMY_SP,
115+
props: vec![
116+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
117+
key: PropName::Str("percentage".into()),
118+
value: Box::new(generate_expr_lit_num!(item.percentage as f64))
119+
}))),
120+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
121+
key: PropName::Str("event".into()),
122+
value: Box::new(Expr::Object(ObjectLit {
123+
span: DUMMY_SP,
124+
props: parse_style_values(item.declarations.clone(), Platform::Harmony)
125+
}))
126+
})))
127+
]
128+
}))
129+
})
130+
}).collect::<Vec<Option<ExprOrSpread>>>()
131+
}))
132+
})))
133+
]
134+
})
135+
)
136+
}
137+
}
138+
PropertyTuple::One(
139+
self.id.to_string(),
140+
generate_invalid_expr!()
141+
)
142+
}
143+
144+
fn to_rn_expr(&self) -> PropertyTuple {
145+
PropertyTuple::One(
146+
self.id.to_string(),
147+
generate_invalid_expr!()
148+
)
149+
}
150+
}
151+

src/style_propetries/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ pub mod background_position;
4343
pub mod background_size;
4444
pub mod background_image;
4545
pub mod background;
46-
pub mod graident_properties;
46+
pub mod graident_properties;
47+
pub mod animation;

src/style_propetries/style_value_type.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::generate_expr_based_on_platform;
22

3-
use super::{aspect_ratio::AspactRatio, background::Background, background_image::BackgroundImage, background_position::BackgroundPosition, background_repeat::BackgroundRepeat, background_size::BackgroundSize, border::Border, border_color::BorderColor, border_radius::BorderRadius, border_style::BorderStyle, border_width::BorderWidth, color::ColorProperty, display::Display, flex::Flex, flex_align::FlexAlign, flex_basis::FlexBasis, flex_direction::FlexDirection, flex_wrap::FlexWrap, font_size::FontSize, font_style::FontStyle, font_weight::FontWeight, gap::Gap, item_align::ItemAlign, length_value::LengthValueProperty, letter_spacing::LetterSpacing, line_height::LineHeight, marin_padding::MarginPadding, max_size::MaxSizeProperty, normal::Normal, number::NumberProperty, overflow::Overflow, size::SizeProperty, text_align::TextAlign, text_decoration::TextDecoration, text_overflow::TextOverflow, text_shadow::TextShadow, text_transform::TextTransform, traits::{ToExpr, ToStyleValue}, transform::Transform, transform_origin::TransformOrigin, unit::{Platform, PropertyTuple}, vertical_align::VerticalAlign};
3+
use super::{animation::Animation, aspect_ratio::AspactRatio, background::Background, background_image::BackgroundImage, background_position::BackgroundPosition, background_repeat::BackgroundRepeat, background_size::BackgroundSize, border::Border, border_color::BorderColor, border_radius::BorderRadius, border_style::BorderStyle, border_width::BorderWidth, color::ColorProperty, display::Display, flex::Flex, flex_align::FlexAlign, flex_basis::FlexBasis, flex_direction::FlexDirection, flex_wrap::FlexWrap, font_size::FontSize, font_style::FontStyle, font_weight::FontWeight, gap::Gap, item_align::ItemAlign, length_value::LengthValueProperty, letter_spacing::LetterSpacing, line_height::LineHeight, marin_padding::MarginPadding, max_size::MaxSizeProperty, normal::Normal, number::NumberProperty, overflow::Overflow, size::SizeProperty, text_align::TextAlign, text_decoration::TextDecoration, text_overflow::TextOverflow, text_shadow::TextShadow, text_transform::TextTransform, traits::{ToExpr, ToStyleValue}, transform::Transform, transform_origin::TransformOrigin, unit::{Platform, PropertyTuple}, vertical_align::VerticalAlign};
44

55

66
#[derive(Debug, Clone)]
@@ -44,7 +44,8 @@ pub enum StyleValueType {
4444
BackgroundPosition(BackgroundPosition),
4545
BackgroundSize(BackgroundSize),
4646
BackgroundImage(BackgroundImage),
47-
Background(Background)
47+
Background(Background),
48+
Animation(Animation)
4849
}
4950

5051
impl ToStyleValue for StyleValueType {
@@ -170,6 +171,9 @@ impl ToStyleValue for StyleValueType {
170171
StyleValueType::Background(value) => {
171172
generate_expr_based_on_platform!(platform, value)
172173
}
174+
StyleValueType::Animation(value) => {
175+
generate_expr_based_on_platform!(platform, value)
176+
}
173177
}
174178
}
175179
}

0 commit comments

Comments
 (0)