#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum SpacingStep {
None,
Xs,
Sm,
Md,
Lg,
Xl,
Xxl,
Custom(u32),
}
impl SpacingStep {
pub fn units(self) -> u32 {
match self {
Self::None => 0,
Self::Xs => 1,
Self::Sm => 2,
Self::Md => 3,
Self::Lg => 4,
Self::Xl => 6,
Self::Xxl => 8,
Self::Custom(value) => value,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct SpacingValue(u32);
impl SpacingValue {
pub fn new(units: u32) -> Self {
Self(units)
}
pub fn from_step(step: SpacingStep) -> Self {
Self(step.units())
}
pub fn units(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct SpacingScale {
unit: u32,
}
impl SpacingScale {
pub fn new(unit: u32) -> Self {
Self { unit }
}
pub fn unit(self) -> u32 {
self.unit
}
pub fn resolve(self, value: SpacingValue) -> u32 {
self.unit.saturating_mul(value.units())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Inset {
pub top: SpacingValue,
pub right: SpacingValue,
pub bottom: SpacingValue,
pub left: SpacingValue,
}
impl Inset {
pub fn all(value: SpacingValue) -> Self {
Self {
top: value,
right: value,
bottom: value,
left: value,
}
}
pub fn symmetric(vertical: SpacingValue, horizontal: SpacingValue) -> Self {
Self {
top: vertical,
right: horizontal,
bottom: vertical,
left: horizontal,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Outset {
pub top: SpacingValue,
pub right: SpacingValue,
pub bottom: SpacingValue,
pub left: SpacingValue,
}
impl Outset {
pub fn all(value: SpacingValue) -> Self {
Self {
top: value,
right: value,
bottom: value,
left: value,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Gap(SpacingValue);
impl Gap {
pub fn new(value: SpacingValue) -> Self {
Self(value)
}
pub fn value(self) -> SpacingValue {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Padding(Inset);
impl Padding {
pub fn new(inset: Inset) -> Self {
Self(inset)
}
pub fn inset(self) -> Inset {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Margin(Outset);
impl Margin {
pub fn new(outset: Outset) -> Self {
Self(outset)
}
pub fn outset(self) -> Outset {
self.0
}
}
#[cfg(test)]
mod tests {
use super::{Gap, Inset, Margin, Outset, Padding, SpacingScale, SpacingStep, SpacingValue};
#[test]
fn resolves_named_spacing_values() {
let scale = SpacingScale::new(4);
let medium = SpacingValue::from_step(SpacingStep::Md);
assert_eq!(SpacingStep::None.units(), 0);
assert_eq!(medium.units(), 3);
assert_eq!(scale.resolve(medium), 12);
assert_eq!(scale.resolve(SpacingValue::from_step(SpacingStep::Xxl)), 32);
}
#[test]
fn creates_box_spacing_primitives() {
let small = SpacingValue::from_step(SpacingStep::Sm);
let large = SpacingValue::from_step(SpacingStep::Lg);
let inset = Inset::symmetric(small, large);
let padding = Padding::new(inset);
let margin = Margin::new(Outset::all(small));
let gap = Gap::new(large);
assert_eq!(padding.inset().top, small);
assert_eq!(padding.inset().right, large);
assert_eq!(margin.outset().left, small);
assert_eq!(gap.value(), large);
}
}