This repository has been archived on 2026-05-05. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
el-ui-retired/crates/el-style/src/spacing.rs
T

138 lines
3.5 KiB
Rust

/// Spacing scale — 4px base grid.
///
/// Use named scale values, not raw numbers. This ensures visual consistency
/// and makes it easy to tweak the entire system by changing the base unit.
/// Named spacing scale values.
///
/// The base unit is 4dp/pt. All values are multiples of 4.
/// Use these for padding, margin, gap, and any other spatial measurement.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Spacing {
/// 0 — no spacing
None,
/// 4dp — hairline gap, tight list items
Xs,
/// 8dp — default tight padding, icon margins
Sm,
/// 12dp — compact component padding
Md,
/// 16dp — standard component padding (the workhorse)
Lg,
/// 24dp — generous padding, card internal spacing
Xl,
/// 32dp — section separation
Xxl,
/// 48dp — hero sections, major layout gaps
Xxxl,
/// 64dp — page-level margins, maximum separation
Max,
/// Custom value in dp (escape hatch)
Custom(u32),
}
impl Spacing {
/// Resolve to a concrete dp/pt value.
pub fn dp(&self) -> u32 {
match self {
Spacing::None => 0,
Spacing::Xs => 4,
Spacing::Sm => 8,
Spacing::Md => 12,
Spacing::Lg => 16,
Spacing::Xl => 24,
Spacing::Xxl => 32,
Spacing::Xxxl => 48,
Spacing::Max => 64,
Spacing::Custom(v) => *v,
}
}
/// Resolve to a concrete CSS pixel string.
pub fn to_css(&self) -> String {
format!("{}px", self.dp())
}
}
/// The spacing scale exposed by a theme.
/// Provides the mapping from scale names to concrete values.
#[derive(Debug, Clone)]
pub struct SpacingScale {
/// Base unit in dp (default: 4).
pub base: u32,
}
impl SpacingScale {
pub fn default() -> Self {
Self { base: 4 }
}
/// Resolve a Spacing token to dp.
pub fn resolve(&self, spacing: &Spacing) -> u32 {
match spacing {
Spacing::Custom(v) => *v,
other => {
let multiplier = match other {
Spacing::None => 0,
Spacing::Xs => 1,
Spacing::Sm => 2,
Spacing::Md => 3,
Spacing::Lg => 4,
Spacing::Xl => 6,
Spacing::Xxl => 8,
Spacing::Xxxl => 12,
Spacing::Max => 16,
Spacing::Custom(_) => unreachable!(),
};
self.base * multiplier
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spacing_none_is_zero() {
assert_eq!(Spacing::None.dp(), 0);
}
#[test]
fn spacing_lg_is_16() {
assert_eq!(Spacing::Lg.dp(), 16);
}
#[test]
fn spacing_max_is_64() {
assert_eq!(Spacing::Max.dp(), 64);
}
#[test]
fn spacing_custom() {
assert_eq!(Spacing::Custom(20).dp(), 20);
}
#[test]
fn spacing_scale_resolves_base_unit() {
let scale = SpacingScale { base: 4 };
assert_eq!(scale.resolve(&Spacing::Xs), 4);
assert_eq!(scale.resolve(&Spacing::Sm), 8);
assert_eq!(scale.resolve(&Spacing::Lg), 16);
}
#[test]
fn spacing_to_css() {
assert_eq!(Spacing::Lg.to_css(), "16px");
assert_eq!(Spacing::None.to_css(), "0px");
}
#[test]
fn spacing_scale_custom_scale() {
let scale = SpacingScale { base: 8 };
assert_eq!(scale.resolve(&Spacing::Xs), 8);
assert_eq!(scale.resolve(&Spacing::Sm), 16);
}
}