Menu
Public repository / master
AkurAI-Framework / crates/css/src/utilities/spacing.rs
Latest change 3aae9f4e85241bcb775c31f5c03094becd3da56a - Pure-Rust UI layer: akurai-ui, akurai-crypto, Tailwind-grade akurai-css by Ólafur Búi Ólafsson
//! Spacing on the 4px scale: padding, margin, gap and `space-*`.
//!
//! `p-2` ⇒ `padding:8px`; steps `0.5`/`1.5`/`2.5`/`3.5`, `px` (1px) and
//! `[arbitrary]` values are accepted, margins also take `auto` and a leading
//! `-` (`-mt-2` ⇒ `margin-top:-8px`).
use super::value::{negate, spacing};
use super::{prefixed, Utility, BETWEEN_CHILDREN};
/// Padding rows, longest prefix first: `(prefix, properties, tier)`.
const PADDING: &[(&str, &[&str], u8)] = &[
("px", &["padding-left", "padding-right"], 1),
("py", &["padding-top", "padding-bottom"], 1),
("pt", &["padding-top"], 2),
("pr", &["padding-right"], 2),
("pb", &["padding-bottom"], 2),
("pl", &["padding-left"], 2),
("p", &["padding"], 0),
];
const MARGIN: &[(&str, &[&str], u8)] = &[
("mx", &["margin-left", "margin-right"], 1),
("my", &["margin-top", "margin-bottom"], 1),
("mt", &["margin-top"], 2),
("mr", &["margin-right"], 2),
("mb", &["margin-bottom"], 2),
("ml", &["margin-left"], 2),
("m", &["margin"], 0),
];
const GAP: &[(&str, &[&str], u8)] = &[
("gap-x", &["column-gap"], 1),
("gap-y", &["row-gap"], 1),
("gap", &["gap"], 0),
];
const SPACE: &[(&str, &[&str], u8)] = &[
("space-x", &["margin-left"], 0),
("space-y", &["margin-top"], 0),
];
pub fn resolve(u: &str) -> Option<Utility> {
prefixed(u, PADDING, spacing)
.or_else(|| prefixed(u, MARGIN, margin_value))
.or_else(|| prefixed(u, GAP, spacing))
.or_else(|| prefixed(u, SPACE, spacing).map(|s| s.child(BETWEEN_CHILDREN)))
}
/// `-m*` and `-space-*`.
pub fn negative(u: &str) -> Option<Utility> {
let neg = |v: &str| spacing(v).and_then(|s| negate(&s));
prefixed(u, MARGIN, neg).or_else(|| prefixed(u, SPACE, neg).map(|s| s.child(BETWEEN_CHILDREN)))
}
fn margin_value(v: &str) -> Option<String> {
if v == "auto" {
return Some("auto".into());
}
spacing(v)
}
#[cfg(test)]
mod tests {
use super::*;
fn decl(u: &str) -> Option<String> {
resolve(u).map(|x| x.declaration())
}
#[test]
fn padding_and_margin() {
assert_eq!(decl("pr-1").as_deref(), Some("padding-right:4px"));
assert_eq!(
decl("my-auto").as_deref(),
Some("margin-top:auto;margin-bottom:auto")
);
assert_eq!(decl("p-auto"), None);
}
#[test]
fn negatives() {
let n = |u: &str| negative(u).map(|x| x.declaration());
assert_eq!(n("mt-2").as_deref(), Some("margin-top:-8px"));
assert_eq!(n("m-0").as_deref(), Some("margin:0px"));
assert_eq!(n("m-auto"), None);
assert_eq!(n("p-2"), None);
assert_eq!(n("m-[3px]").as_deref(), Some("margin:-3px"));
}
#[test]
fn space_has_child_selector() {
let s = resolve("space-y-2").unwrap();
assert_eq!(s.child, Some(BETWEEN_CHILDREN));
assert_eq!(s.declaration(), "margin-top:8px");
}
}