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

View File

@ -2,8 +2,14 @@ use std::collections::HashMap;
use crate::SpecialDeclaration; 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> { pub(crate) fn default_declarations() -> HashMap<String, String> {
vec![ vec_to_hashmap(&[
("flex", "display:flex"), ("flex", "display:flex"),
("flex-row", "display:flex;flex-direction:row"), ("flex-row", "display:flex;flex-direction:row"),
("flex-col", "display:flex;flex-direction:column"), ("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-left", "text-align:left"),
("text-right", "text-align:right"), ("text-right", "text-align:right"),
// TODO // TODO
] ])
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect::<HashMap<_, _>>()
} }
pub(crate) fn default_properties() -> HashMap<String, String> { pub(crate) fn default_properties() -> HashMap<String, String> {
vec![ vec_to_hashmap(&[
("w", "width"), ("w", "width"),
("h", "height"), ("h", "height"),
("m", "margin"), ("m", "margin"),
@ -36,47 +39,89 @@ pub(crate) fn default_properties() -> HashMap<String, String> {
("pb", "padding-bottom"), ("pb", "padding-bottom"),
("pl", "padding-left"), ("pl", "padding-left"),
("pr", "padding-right"), ("pr", "padding-right"),
("c", "color"),
("bg", "background"), ("bg", "background"),
("bgc", "background-color"), ("bgc", "background-color"),
("tt", "text-transform"),
("td", "text-decoration"),
// TODO // TODO
] ])
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
} }
pub(crate) fn default_values() -> HashMap<String, String> { pub(crate) fn default_values() -> HashMap<String, String> {
vec![ vec_to_hashmap(&[
("full", "100%"), ("full", "100%"),
// TODO // 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() .into_iter()
.map(|(a, b)| (a.to_string(), b.to_string())) .map(|(n, h)| (n.to_string(), vec_to_hashmap(h)))
.collect() .collect()
} }
pub(crate) fn default_modifiers() -> HashMap<String, String> { pub(crate) fn default_modifiers() -> HashMap<String, String> {
vec![ vec_to_hashmap(&[
("odd", "nth-child(odd)"), ("odd", "nth-child(odd)"),
("even", "nth-child(even)"), ("even", "nth-child(even)"),
("first", "first-child"), ("first", "first-child"),
("last", "last-child"), ("last", "last-child"),
("only", "only-child"), ("only", "only-child"),
// TODO // TODO
] ])
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
} }
pub(crate) fn default_pseudos() -> HashMap<String, String> { pub(crate) fn default_pseudos() -> HashMap<String, String> {
vec![ vec_to_hashmap(&[
("ph", "placeholder"), ("ph", "placeholder"),
// TODO // TODO
] ])
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
} }
macro_rules! special { macro_rules! special {
@ -91,11 +136,11 @@ macro_rules! special {
} }
pub(crate) fn default_specials() -> HashMap<String, SpecialDeclaration> { pub(crate) fn default_specials() -> HashMap<String, SpecialDeclaration> {
vec![ [
special!("mx", val, "margin-left:{val};margin-right:{val};"), special!("mx", val, "margin-left:{val};margin-right:{val}"),
special!("my", val, "margin-top:{val};margin-bottom:{val};"), special!("my", val, "margin-top:{val};margin-bottom:{val}"),
special!("px", val, "padding-left:{val};padding-right:{val};"), special!("px", val, "padding-left:{val};padding-right:{val}"),
special!("py", val, "padding-top:{val};padding-bottom:{val};"), special!("py", val, "padding-top:{val};padding-bottom:{val}"),
special!("wh", val, "width:{val};height:{val};"), special!("wh", val, "width:{val};height:{val};"),
// TODO // TODO
] ]

View File

@ -35,6 +35,10 @@ pub struct Zephyr {
pub modifiers: HashMap<String, String>, pub modifiers: HashMap<String, String>,
/// list of pseudo-element short-hands /// list of pseudo-element short-hands
pub pseudos: HashMap<String, String>, 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 /// value -> declarations
@ -108,6 +112,7 @@ impl Zephyr {
modifiers: default_modifiers(), modifiers: default_modifiers(),
pseudos: default_pseudos(), pseudos: default_pseudos(),
specials: default_specials(), 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, value_type: class::ValueType::Normal,
}; };
let css = class.generate(&z).unwrap(); 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 { let class = Class {
property: "m", property: "m",
@ -25,7 +25,7 @@ fn generate_margin_works() {
value_type: class::ValueType::Normal, value_type: class::ValueType::Normal,
}; };
let css = class.generate(&z).unwrap(); 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 { let class = Class {
property: "m", property: "m",
@ -38,7 +38,7 @@ fn generate_margin_works() {
let css = class.generate(&z).unwrap(); let css = class.generate(&z).unwrap();
assert_eq!( assert_eq!(
css, 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"]); let classes = z.generate_classes(["m[3rem]hover,focus$placeholder"]);
assert_eq!( assert_eq!(
classes, 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"]); 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]"]); 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] #[test]
@ -73,7 +73,7 @@ fn generate_multiple_works() {
let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]); let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]);
assert_eq!( assert_eq!(
classes_joined, 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); assert_eq!(classes_separate, classes_joined);
} }
@ -85,7 +85,7 @@ fn generate_specials_works() {
let classes = z.generate_classes(["mx[1rem]"]); let classes = z.generate_classes(["mx[1rem]"]);
assert_eq!( assert_eq!(
classes, 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]"]); let classes = z.generate_classes(["border[1px_solid_black]"]);
assert_eq!( assert_eq!(
classes, 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}"]); let classes = z.generate_classes(["border{1px_solid_black}", "w{full}"]);
assert_eq!( assert_eq!(
classes, 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"]); let classes = z.generate_classes(["m[1rem]sm"]);
assert_eq!( assert_eq!(
classes, 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(--...)` // the parens indicate that it should be replaced by `var(--...)`
let classes = z.generate_classes(["m(my-margin)"]); 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] #[test]
@ -142,3 +142,11 @@ fn generate_css_colors() {
r#".white{color:white}.blanchedalmond{color:blanchedalmond}"# 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}"#);
}