context aware values

This commit is contained in:
annieversary 2022-08-15 15:05:03 +01:00
parent d985d71fa4
commit 871fce954d
4 changed files with 111 additions and 40 deletions

View File

@ -21,10 +21,16 @@ pub(crate) struct Class<'a> {
#[derive(PartialEq, Debug)]
pub(crate) enum ValueType {
/// replacements will be performed
///
/// eg: `m[1rem]`
Normal,
/// no replacements will be done. value will be output as-is
///
/// eg: `border{1px solid black}`
Literal,
/// value will be output as `var(--value)`, without any replacements
///
/// eg: `c(main-color)`
Variable,
}
@ -86,7 +92,14 @@ impl<'a> Class<'a> {
if let Some(val) = self.value {
let val = match self.value_type {
ValueType::Normal => {
replace_underscores(z.values.get(val).map(AsRef::as_ref).unwrap_or(val))
let v = z
.context_aware_values
.get(property)
.and_then(|h| h.get(val))
.or_else(|| z.values.get(val))
.map(AsRef::as_ref)
.unwrap_or(val);
replace_underscores(v)
}
ValueType::Literal => val.into(),
ValueType::Variable => format!("var(--{val})").into(),
@ -96,7 +109,7 @@ impl<'a> Class<'a> {
let v = fun(&val);
Ok(format!("{selector}{{{v}}}",))
} else {
Ok(format!("{selector}{{{property}:{val};}}"))
Ok(format!("{selector}{{{property}:{val}}}"))
}
} else if let Some(v) = z.declarations.get(property) {
Ok(format!("{selector}{{{v}}}"))

View File

@ -2,8 +2,14 @@ use std::collections::HashMap;
use crate::SpecialDeclaration;
fn vec_to_hashmap(v: &[(&str, &str)]) -> HashMap<String, String> {
v.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect::<HashMap<_, _>>()
}
pub(crate) fn default_declarations() -> HashMap<String, String> {
vec![
vec_to_hashmap(&[
("flex", "display:flex"),
("flex-row", "display:flex;flex-direction:row"),
("flex-col", "display:flex;flex-direction:column"),
@ -16,14 +22,11 @@ pub(crate) fn default_declarations() -> HashMap<String, String> {
("text-left", "text-align:left"),
("text-right", "text-align:right"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect::<HashMap<_, _>>()
])
}
pub(crate) fn default_properties() -> HashMap<String, String> {
vec![
vec_to_hashmap(&[
("w", "width"),
("h", "height"),
("m", "margin"),
@ -36,47 +39,89 @@ pub(crate) fn default_properties() -> HashMap<String, String> {
("pb", "padding-bottom"),
("pl", "padding-left"),
("pr", "padding-right"),
("c", "color"),
("bg", "background"),
("bgc", "background-color"),
("tt", "text-transform"),
("td", "text-decoration"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
])
}
pub(crate) fn default_values() -> HashMap<String, String> {
vec![
vec_to_hashmap(&[
("full", "100%"),
// TODO
])
}
pub(crate) fn default_context_aware_values() -> HashMap<String, HashMap<String, String>> {
[
(
"text-decoration",
&[
("u", "underline"),
("ud", "underline dotted"),
("uw", "underline wavy"),
("o", "overline"),
("od", "overline dotted"),
("ow", "overline wavy"),
] as &[(&str, &str)],
),
(
"text-transform",
&[("c", "capitalize"), ("u", "uppercase"), ("l", "lowercase")],
),
(
"overflow",
&[
("v", "visible"),
("h", "hidden"),
("s", "scroll"),
("c", "clip"),
],
),
(
"overflow-x",
&[
("v", "visible"),
("h", "hidden"),
("s", "scroll"),
("c", "clip"),
],
),
(
"overflow-y",
&[
("v", "visible"),
("h", "hidden"),
("s", "scroll"),
("c", "clip"),
],
),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.map(|(n, h)| (n.to_string(), vec_to_hashmap(h)))
.collect()
}
pub(crate) fn default_modifiers() -> HashMap<String, String> {
vec![
vec_to_hashmap(&[
("odd", "nth-child(odd)"),
("even", "nth-child(even)"),
("first", "first-child"),
("last", "last-child"),
("only", "only-child"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
])
}
pub(crate) fn default_pseudos() -> HashMap<String, String> {
vec![
vec_to_hashmap(&[
("ph", "placeholder"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
])
}
macro_rules! special {
@ -91,11 +136,11 @@ macro_rules! special {
}
pub(crate) fn default_specials() -> HashMap<String, SpecialDeclaration> {
vec![
special!("mx", val, "margin-left:{val};margin-right:{val};"),
special!("my", val, "margin-top:{val};margin-bottom:{val};"),
special!("px", val, "padding-left:{val};padding-right:{val};"),
special!("py", val, "padding-top:{val};padding-bottom:{val};"),
[
special!("mx", val, "margin-left:{val};margin-right:{val}"),
special!("my", val, "margin-top:{val};margin-bottom:{val}"),
special!("px", val, "padding-left:{val};padding-right:{val}"),
special!("py", val, "padding-top:{val};padding-bottom:{val}"),
special!("wh", val, "width:{val};height:{val};"),
// TODO
]

View File

@ -35,6 +35,10 @@ pub struct Zephyr {
pub modifiers: HashMap<String, String>,
/// list of pseudo-element short-hands
pub pseudos: HashMap<String, String>,
/// list of value replacements for each property
///
/// property -> [(short, expanded)]
pub context_aware_values: HashMap<String, HashMap<String, String>>,
}
/// value -> declarations
@ -108,6 +112,7 @@ impl Zephyr {
modifiers: default_modifiers(),
pseudos: default_pseudos(),
specials: default_specials(),
context_aware_values: default_context_aware_values(),
}
}

View File

@ -14,7 +14,7 @@ fn generate_margin_works() {
value_type: class::ValueType::Normal,
};
let css = class.generate(&z).unwrap();
assert_eq!(css, r#".m\[1rem\]{margin:1rem;}"#);
assert_eq!(css, r#".m\[1rem\]{margin:1rem}"#);
let class = Class {
property: "m",
@ -25,7 +25,7 @@ fn generate_margin_works() {
value_type: class::ValueType::Normal,
};
let css = class.generate(&z).unwrap();
assert_eq!(css, r#".m\[1rem\]focus:focus{margin:1rem;}"#);
assert_eq!(css, r#".m\[1rem\]focus:focus{margin:1rem}"#);
let class = Class {
property: "m",
@ -38,7 +38,7 @@ fn generate_margin_works() {
let css = class.generate(&z).unwrap();
assert_eq!(
css,
r#".m\[1rem\]focus,hover,odd:focus:hover:nth-child\(odd\){margin:1rem;}"#
r#".m\[1rem\]focus,hover,odd:focus:hover:nth-child\(odd\){margin:1rem}"#
);
}
@ -52,7 +52,7 @@ fn generate_classes_works() {
let classes = z.generate_classes(["m[3rem]hover,focus$placeholder"]);
assert_eq!(
classes,
r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder{margin:3rem;}"#
r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder{margin:3rem}"#
);
let classes = z.generate_classes(["flex|hover,focus$placeholder"]);
@ -62,7 +62,7 @@ fn generate_classes_works() {
);
let classes = z.generate_classes(["mr[0.5rem]"]);
assert_eq!(classes, r#".mr\[0\.5rem\]{margin-right:0.5rem;}"#);
assert_eq!(classes, r#".mr\[0\.5rem\]{margin-right:0.5rem}"#);
}
#[test]
@ -73,7 +73,7 @@ fn generate_multiple_works() {
let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]);
assert_eq!(
classes_joined,
r#".flex-row{display:flex;flex-direction:row}.mt\[1rem\]{margin-top:1rem;}"#
r#".flex-row{display:flex;flex-direction:row}.mt\[1rem\]{margin-top:1rem}"#
);
assert_eq!(classes_separate, classes_joined);
}
@ -85,7 +85,7 @@ fn generate_specials_works() {
let classes = z.generate_classes(["mx[1rem]"]);
assert_eq!(
classes,
r#".mx\[1rem\]{margin-left:1rem;margin-right:1rem;}"#
r#".mx\[1rem\]{margin-left:1rem;margin-right:1rem}"#
);
}
@ -96,7 +96,7 @@ fn generate_with_spaces_works() {
let classes = z.generate_classes(["border[1px_solid_black]"]);
assert_eq!(
classes,
r#".border\[1px_solid_black\]{border:1px solid black;}"#
r#".border\[1px_solid_black\]{border:1px solid black}"#
);
}
@ -108,7 +108,7 @@ fn generate_literals_works() {
let classes = z.generate_classes(["border{1px_solid_black}", "w{full}"]);
assert_eq!(
classes,
r#".border\{1px_solid_black\}{border:1px_solid_black;}.w\{full\}{width:full;}"#
r#".border\{1px_solid_black\}{border:1px_solid_black}.w\{full\}{width:full}"#
);
}
@ -119,7 +119,7 @@ fn generate_with_media_query() {
let classes = z.generate_classes(["m[1rem]sm"]);
assert_eq!(
classes,
r#"@media(min-width:640px){.m\[1rem\]sm{margin:1rem;}}"#
r#"@media(min-width:640px){.m\[1rem\]sm{margin:1rem}}"#
);
}
@ -129,7 +129,7 @@ fn generate_variable() {
// the parens indicate that it should be replaced by `var(--...)`
let classes = z.generate_classes(["m(my-margin)"]);
assert_eq!(classes, r#".m\(my-margin\){margin:var(--my-margin);}"#);
assert_eq!(classes, r#".m\(my-margin\){margin:var(--my-margin)}"#);
}
#[test]
@ -142,3 +142,11 @@ fn generate_css_colors() {
r#".white{color:white}.blanchedalmond{color:blanchedalmond}"#
);
}
#[test]
fn generate_context_aware_value() {
let z = Zephyr::new();
let classes = z.generate_classes(["tt[u]"]);
assert_eq!(classes, r#".tt\[u\]{text-transform:uppercase}"#);
}