Skip to content

Commit ffbc913

Browse files
committed
Implement global css
1 parent 83f1b81 commit ffbc913

File tree

43 files changed

+1901
-150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1901
-150
lines changed

bindings/devup-ui-wasm/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ impl Output {
4444
let mut collected = false;
4545
for style in self.styles.iter() {
4646
let (cls, variable) = match style.extract() {
47-
StyleProperty::ClassName(cls) => (cls, None),
48-
StyleProperty::Variable {
47+
Some(StyleProperty::ClassName(cls)) => (cls, None),
48+
Some(StyleProperty::Variable {
4949
class_name,
5050
variable_name,
5151
..
52-
} => (class_name, Some(variable_name)),
52+
}) => (class_name, Some(variable_name)),
53+
None => continue,
5354
};
5455
match style {
5556
ExtractStyleValue::Static(st) => {
@@ -82,6 +83,9 @@ impl Output {
8283
}
8384
}
8485
ExtractStyleValue::Typography(_) => {}
86+
ExtractStyleValue::Import(st) => {
87+
sheet.add_import(st);
88+
}
8589
}
8690
}
8791
if !collected {

libs/css/src/lib.rs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static SELECTOR_ORDER_MAP: Lazy<HashMap<String, u8>> = Lazy::new(|| {
2121
.into_iter()
2222
.enumerate()
2323
{
24-
map.insert(format!("&:{selector}"), idx as u8);
24+
map.insert(format!(":{selector}"), idx as u8);
2525
}
2626
map
2727
});
@@ -41,6 +41,7 @@ pub fn is_debug() -> bool {
4141
pub enum StyleSelector {
4242
Media(String),
4343
Selector(String),
44+
Global(String),
4445
}
4546

4647
impl PartialOrd for StyleSelector {
@@ -55,7 +56,7 @@ fn get_selector_order(selector: &str) -> u8 {
5556
selector
5657
.split('&')
5758
.next_back()
58-
.map(|a| format!("&{a}"))
59+
.map(|a| format!("{a}"))
5960
.unwrap_or(selector.to_string())
6061
} else {
6162
selector.to_string()
@@ -75,6 +76,37 @@ impl Ord for StyleSelector {
7576
}
7677
(StyleSelector::Media(_), StyleSelector::Selector(_)) => Ordering::Greater,
7778
(StyleSelector::Selector(_), StyleSelector::Media(_)) => Ordering::Less,
79+
(StyleSelector::Global(a), StyleSelector::Global(b)) => {
80+
if a == b {
81+
return Ordering::Equal;
82+
}
83+
match (a.contains(":"), b.contains(":")) {
84+
(true, true) => {
85+
let a_order = a.split(":").next().unwrap();
86+
let b_order = b.split(":").next().unwrap();
87+
let mut a_order_value = 0;
88+
let mut b_order_value = 0;
89+
for (order, order_value) in SELECTOR_ORDER_MAP.iter() {
90+
if a_order.contains(order) {
91+
a_order_value = *order_value;
92+
}
93+
if b_order.contains(order) {
94+
b_order_value = *order_value;
95+
}
96+
}
97+
if a_order_value == b_order_value {
98+
a.cmp(b)
99+
} else {
100+
a_order_value.cmp(&b_order_value)
101+
}
102+
}
103+
(true, false) => Ordering::Greater,
104+
(false, true) => Ordering::Less,
105+
(false, false) => a.cmp(b),
106+
}
107+
}
108+
(StyleSelector::Global(_), _) => Ordering::Less,
109+
(_, StyleSelector::Global(_)) => Ordering::Greater,
78110
}
79111
}
80112
}
@@ -121,6 +153,21 @@ impl From<[&str; 2]> for StyleSelector {
121153
))
122154
}
123155
}
156+
impl From<(&StyleSelector, &str)> for StyleSelector {
157+
fn from(value: (&StyleSelector, &str)) -> Self {
158+
if let StyleSelector::Global(_) = value.0 {
159+
let post = to_kebab_case(value.1);
160+
StyleSelector::Global(format!(
161+
"{}{}{}",
162+
value.0,
163+
get_selector_separator(&post),
164+
post
165+
))
166+
} else {
167+
StyleSelector::from([&value.0.to_string(), value.1])
168+
}
169+
}
170+
}
124171

125172
impl Display for StyleSelector {
126173
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
@@ -130,6 +177,7 @@ impl Display for StyleSelector {
130177
match self {
131178
StyleSelector::Selector(value) => value.to_string(),
132179
StyleSelector::Media(value) => format!("@{value}"),
180+
StyleSelector::Global(value) => format!("{value}"),
133181
}
134182
)
135183
}
@@ -140,6 +188,7 @@ pub fn merge_selector(class_name: &str, selector: Option<&StyleSelector>) -> Str
140188
match selector {
141189
StyleSelector::Selector(value) => value.replace("&", &format!(".{class_name}")),
142190
StyleSelector::Media(_) => format!(".{class_name}"),
191+
StyleSelector::Global(v) => format!("{v}"),
143192
}
144193
} else {
145194
format!(".{class_name}")
@@ -468,13 +517,11 @@ pub fn sheet_to_variable_name(property: &str, level: u8, selector: Option<&str>)
468517
} else {
469518
let key = format!("{}-{}-{}", property, level, selector.unwrap_or("").trim());
470519
let mut map = GLOBAL_CLASS_MAP.lock().unwrap();
471-
map.get(&key)
472-
.map(|v| format!("--d{v}"))
473-
.unwrap_or_else(|| {
474-
let len = map.len();
475-
map.insert(key, len as i32);
476-
format!("--d{}", map.len() - 1)
477-
})
520+
map.get(&key).map(|v| format!("--d{v}")).unwrap_or_else(|| {
521+
let len = map.len();
522+
map.insert(key, len as i32);
523+
format!("--d{}", map.len() - 1)
524+
})
478525
}
479526
}
480527

libs/extractor/src/css_type.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#[derive(Debug)]
2+
pub enum CssType {
3+
Css,
4+
GlobalCss,
5+
}
6+
7+
impl TryFrom<String> for CssType {
8+
type Error = String;
9+
10+
fn try_from(value: String) -> Result<Self, Self::Error> {
11+
if value == "css" {
12+
Ok(CssType::Css)
13+
} else if value == "globalCss" {
14+
Ok(CssType::GlobalCss)
15+
} else {
16+
Err(value)
17+
}
18+
}
19+
}

libs/extractor/src/css_utils.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use css::{StyleSelector, to_camel_case};
2+
3+
use crate::{
4+
ExtractStyleProp,
5+
extract_style::{ExtractStaticStyle, ExtractStyleValue},
6+
};
7+
pub fn css_to_style<'a>(
8+
css: &str,
9+
level: u8,
10+
selector: &Option<&StyleSelector>,
11+
) -> Vec<ExtractStyleProp<'a>> {
12+
let mut styles = vec![];
13+
for s in css.split(";") {
14+
let mut iter = s.split(":");
15+
let property = to_camel_case(iter.next().unwrap().trim());
16+
let value = iter.next().unwrap().trim();
17+
styles.push(ExtractStyleProp::Static(ExtractStyleValue::Static(
18+
ExtractStaticStyle::new(&property, value, level, selector.cloned()),
19+
)));
20+
}
21+
styles
22+
}
23+
24+
pub fn optimize_css_block(css: &str) -> String {
25+
css.split("{")
26+
.map(|s| s.trim().to_string())
27+
.collect::<Vec<String>>()
28+
.join("{")
29+
.split("}")
30+
.map(|s| s.trim().to_string())
31+
.collect::<Vec<String>>()
32+
.join("}")
33+
.split(";")
34+
.map(|s| {
35+
if !s.contains(":") {
36+
s.to_string().trim().to_string()
37+
} else {
38+
let mut iter = s.split(":");
39+
let property = iter.next().unwrap().trim();
40+
let value = iter.next().unwrap().trim();
41+
format!("{}:{}", property, value)
42+
}
43+
})
44+
.collect::<Vec<String>>()
45+
.join(";")
46+
.trim()
47+
.replace(";}", "}")
48+
.to_string()
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
55+
#[test]
56+
fn test_optimize_css_block() {
57+
assert_eq!(
58+
optimize_css_block(
59+
" img { background-color : red; } "
60+
),
61+
"img{background-color:red}"
62+
);
63+
assert_eq!(
64+
optimize_css_block(
65+
" img { background-color : red; color : blue; } "
66+
),
67+
"img{background-color:red;color:blue}"
68+
);
69+
}
70+
}

libs/extractor/src/extract_style/mod.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl ExtractStyleProperty for ExtractStaticStyle {
122122
}
123123
#[derive(Debug, PartialEq, Clone, Eq, Hash, Ord, PartialOrd)]
124124
pub struct ExtractCss {
125-
/// css code
125+
/// css must be global css
126126
pub css: String,
127127
}
128128

@@ -211,17 +211,19 @@ pub enum ExtractStyleValue {
211211
Typography(String),
212212
Dynamic(ExtractDynamicStyle),
213213
Css(ExtractCss),
214+
Import(String),
214215
}
215216

216217
impl ExtractStyleValue {
217-
pub fn extract(&self) -> StyleProperty {
218+
pub fn extract(&self) -> Option<StyleProperty> {
218219
match self {
219-
ExtractStyleValue::Static(style) => style.extract(),
220-
ExtractStyleValue::Dynamic(style) => style.extract(),
221-
ExtractStyleValue::Css(css) => css.extract(),
220+
ExtractStyleValue::Static(style) => Some(style.extract()),
221+
ExtractStyleValue::Dynamic(style) => Some(style.extract()),
222+
ExtractStyleValue::Css(css) => Some(css.extract()),
222223
ExtractStyleValue::Typography(typo) => {
223-
StyleProperty::ClassName(format!("typo-{typo}"))
224+
Some(StyleProperty::ClassName(format!("typo-{typo}")))
224225
}
226+
ExtractStyleValue::Import(_) => None,
225227
}
226228
}
227229
pub fn set_style_order(&mut self, order: u8) {

libs/extractor/src/gen_class_name.rs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use crate::prop_modify_utils::convert_class_name;
22
use crate::{ExtractStyleProp, StyleProperty};
33
use oxc_allocator::CloneIn;
44
use oxc_ast::AstBuilder;
5-
use oxc_ast::ast::{
6-
Expression, PropertyKey, PropertyKind, TemplateElement,
7-
TemplateElementValue,
8-
};
5+
use oxc_ast::ast::{Expression, PropertyKey, PropertyKind, TemplateElement, TemplateElementValue};
96
use oxc_span::SPAN;
107

118
pub fn gen_class_names<'a>(
@@ -38,8 +35,9 @@ fn gen_class_name<'a>(
3835
Some(ast_builder.expression_string_literal(
3936
SPAN,
4037
ast_builder.atom(match &target {
41-
StyleProperty::ClassName(cls) => cls,
42-
StyleProperty::Variable { class_name, .. } => class_name,
38+
Some(StyleProperty::ClassName(cls)) => cls,
39+
Some(StyleProperty::Variable { class_name, .. }) => class_name,
40+
None => return None,
4341
}),
4442
None,
4543
))
@@ -141,13 +139,10 @@ pub fn merge_expression_for_class_name<'a>(
141139
let mut class_names = vec![];
142140
let mut unknown_expr = vec![];
143141
for expr in expressions {
144-
match expr {
145-
Expression::StringLiteral(str) => {
146-
class_names.push(str.value.to_string().trim().to_string())
147-
}
148-
_ => {
149-
unknown_expr.push(expr);
150-
}
142+
if let Expression::StringLiteral(str) = &expr {
143+
class_names.push(str.value.to_string().trim().to_string())
144+
} else {
145+
unknown_expr.push(expr);
151146
}
152147
}
153148
if unknown_expr.is_empty() && class_names.is_empty() {
@@ -175,26 +170,16 @@ pub fn merge_expression_for_class_name<'a>(
175170
tail: false,
176171
lone_surrogates: false,
177172
});
178-
} else if idx == unknown_expr.len() {
179-
qu.push(TemplateElement {
180-
span: SPAN,
181-
value: TemplateElementValue {
182-
raw: ast_builder.atom(""),
183-
cooked: None,
184-
},
185-
tail: true,
186-
lone_surrogates: false,
187-
});
188173
} else {
189-
qu.push(TemplateElement {
190-
span: SPAN,
191-
value: TemplateElementValue {
192-
raw: ast_builder.atom(" "),
174+
let tail = idx == unknown_expr.len();
175+
qu.push(ast_builder.template_element(
176+
SPAN,
177+
TemplateElementValue {
178+
raw: ast_builder.atom(if tail { "" } else { " " }),
193179
cooked: None,
194180
},
195-
tail: false,
196-
lone_surrogates: false,
197-
});
181+
tail,
182+
));
198183
}
199184
}
200185

0 commit comments

Comments
 (0)