use crate::classes::ClassBuilder;
use crate::utilities::spacing::SpacingValue;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum LogicalDirection {
InlineStart,
InlineEnd,
BlockStart,
BlockEnd,
}
impl fmt::Display for LogicalDirection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LogicalDirection::InlineStart => write!(f, "inline-start"),
LogicalDirection::InlineEnd => write!(f, "inline-end"),
LogicalDirection::BlockStart => write!(f, "block-start"),
LogicalDirection::BlockEnd => write!(f, "block-end"),
}
}
}
pub trait LogicalPropertiesUtilities {
fn margin_inline_start(self, value: SpacingValue) -> Self;
fn margin_inline_end(self, value: SpacingValue) -> Self;
fn margin_block_start(self, value: SpacingValue) -> Self;
fn margin_block_end(self, value: SpacingValue) -> Self;
fn padding_inline_start(self, value: SpacingValue) -> Self;
fn padding_inline_end(self, value: SpacingValue) -> Self;
fn padding_block_start(self, value: SpacingValue) -> Self;
fn padding_block_end(self, value: SpacingValue) -> Self;
fn border_inline_start(self, value: SpacingValue) -> Self;
fn border_inline_end(self, value: SpacingValue) -> Self;
fn border_block_start(self, value: SpacingValue) -> Self;
fn border_block_end(self, value: SpacingValue) -> Self;
fn inset_inline_start(self, value: SpacingValue) -> Self;
fn inset_inline_end(self, value: SpacingValue) -> Self;
fn inset_block_start(self, value: SpacingValue) -> Self;
fn inset_block_end(self, value: SpacingValue) -> Self;
}
impl LogicalPropertiesUtilities for ClassBuilder {
fn margin_inline_start(self, value: SpacingValue) -> Self {
let class_name = format!("ms-{}", value);
self.class(class_name)
}
fn margin_inline_end(self, value: SpacingValue) -> Self {
let class_name = format!("me-{}", value);
self.class(class_name)
}
fn margin_block_start(self, value: SpacingValue) -> Self {
let class_name = format!("mt-{}", value);
self.class(class_name)
}
fn margin_block_end(self, value: SpacingValue) -> Self {
let class_name = format!("mb-{}", value);
self.class(class_name)
}
fn padding_inline_start(self, value: SpacingValue) -> Self {
let class_name = format!("ps-{}", value);
self.class(class_name)
}
fn padding_inline_end(self, value: SpacingValue) -> Self {
let class_name = format!("pe-{}", value);
self.class(class_name)
}
fn padding_block_start(self, value: SpacingValue) -> Self {
let class_name = format!("pt-{}", value);
self.class(class_name)
}
fn padding_block_end(self, value: SpacingValue) -> Self {
let class_name = format!("pb-{}", value);
self.class(class_name)
}
fn border_inline_start(self, value: SpacingValue) -> Self {
let class_name = format!("border-s-{}", value);
self.class(class_name)
}
fn border_inline_end(self, value: SpacingValue) -> Self {
let class_name = format!("border-e-{}", value);
self.class(class_name)
}
fn border_block_start(self, value: SpacingValue) -> Self {
let class_name = format!("border-t-{}", value);
self.class(class_name)
}
fn border_block_end(self, value: SpacingValue) -> Self {
let class_name = format!("border-b-{}", value);
self.class(class_name)
}
fn inset_inline_start(self, value: SpacingValue) -> Self {
let class_name = format!("start-{}", value);
self.class(class_name)
}
fn inset_inline_end(self, value: SpacingValue) -> Self {
let class_name = format!("end-{}", value);
self.class(class_name)
}
fn inset_block_start(self, value: SpacingValue) -> Self {
let class_name = format!("top-{}", value);
self.class(class_name)
}
fn inset_block_end(self, value: SpacingValue) -> Self {
let class_name = format!("bottom-{}", value);
self.class(class_name)
}
}
pub trait LogicalPropertiesConvenience {
fn margin_inline_start_4(self) -> Self;
fn margin_inline_end_4(self) -> Self;
fn padding_inline_start_2(self) -> Self;
fn padding_inline_end_2(self) -> Self;
fn padding_inline_start_4(self) -> Self;
fn padding_inline_end_4(self) -> Self;
fn border_inline_start_1(self) -> Self;
fn border_inline_end_1(self) -> Self;
fn border_inline_start_2(self) -> Self;
fn border_inline_end_2(self) -> Self;
}
impl LogicalPropertiesConvenience for ClassBuilder {
fn margin_inline_start_4(self) -> Self {
self.margin_inline_start(SpacingValue::Integer(4))
}
fn margin_inline_end_4(self) -> Self {
self.margin_inline_end(SpacingValue::Integer(4))
}
fn padding_inline_start_2(self) -> Self {
self.padding_inline_start(SpacingValue::Integer(2))
}
fn padding_inline_end_2(self) -> Self {
self.padding_inline_end(SpacingValue::Integer(2))
}
fn border_inline_start_1(self) -> Self {
self.border_inline_start(SpacingValue::Integer(1))
}
fn border_inline_end_1(self) -> Self {
self.border_inline_end(SpacingValue::Integer(1))
}
fn padding_inline_start_4(self) -> Self {
self.padding_inline_start(SpacingValue::Integer(4))
}
fn padding_inline_end_4(self) -> Self {
self.padding_inline_end(SpacingValue::Integer(4))
}
fn border_inline_start_2(self) -> Self {
self.border_inline_start(SpacingValue::Integer(2))
}
fn border_inline_end_2(self) -> Self {
self.border_inline_end(SpacingValue::Integer(2))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::classes::ClassBuilder;
use crate::utilities::spacing::SpacingValue;
#[test]
fn test_logical_direction_enum_values() {
assert_eq!(LogicalDirection::InlineStart.to_string(), "inline-start");
assert_eq!(LogicalDirection::InlineEnd.to_string(), "inline-end");
assert_eq!(LogicalDirection::BlockStart.to_string(), "block-start");
assert_eq!(LogicalDirection::BlockEnd.to_string(), "block-end");
}
#[test]
fn test_logical_properties_utilities() {
let classes = ClassBuilder::new()
.margin_inline_start(SpacingValue::Integer(4))
.margin_inline_end(SpacingValue::Integer(4))
.padding_inline_start(SpacingValue::Integer(2))
.padding_inline_end(SpacingValue::Integer(2))
.border_inline_start(SpacingValue::Integer(1))
.border_inline_end(SpacingValue::Integer(1));
let result = classes.build();
assert!(result.classes.contains("ms-4"));
assert!(result.classes.contains("me-4"));
assert!(result.classes.contains("ps-2"));
assert!(result.classes.contains("pe-2"));
assert!(result.classes.contains("border-s-1"));
assert!(result.classes.contains("border-e-1"));
}
#[test]
fn test_logical_properties_convenience() {
let classes = ClassBuilder::new()
.margin_inline_start_4()
.margin_inline_end_4()
.padding_inline_start_4()
.padding_inline_end_4()
.border_inline_start_2()
.border_inline_end_2();
let result = classes.build();
assert!(result.classes.contains("ms-4"));
assert!(result.classes.contains("me-4"));
assert!(result.classes.contains("ps-4"));
assert!(result.classes.contains("pe-4"));
assert!(result.classes.contains("border-s-2"));
assert!(result.classes.contains("border-e-2"));
}
#[test]
fn test_logical_properties_serialization() {
let direction = LogicalDirection::InlineStart;
let serialized = serde_json::to_string(&direction).unwrap();
let deserialized: LogicalDirection = serde_json::from_str(&serialized).unwrap();
assert_eq!(direction, deserialized);
}
#[test]
fn test_logical_properties_comprehensive_usage() {
let classes = ClassBuilder::new()
.margin_inline_start_4()
.margin_inline_end_4()
.padding_inline_start_2()
.padding_inline_end_2()
.border_inline_start_1()
.border_inline_end_1();
let result = classes.build();
assert!(result.classes.contains("ms-4"));
assert!(result.classes.contains("me-4"));
assert!(result.classes.contains("ps-2"));
assert!(result.classes.contains("pe-2"));
assert!(result.classes.contains("border-s-1"));
assert!(result.classes.contains("border-e-1"));
}
#[test]
fn test_logical_properties_with_different_spacing_values() {
let classes = ClassBuilder::new()
.margin_inline_start(SpacingValue::Integer(8))
.margin_inline_end(SpacingValue::Integer(12))
.padding_inline_start(SpacingValue::Integer(6))
.padding_inline_end(SpacingValue::Integer(10));
let result = classes.build();
assert!(result.classes.contains("ms-8"));
assert!(result.classes.contains("me-12"));
assert!(result.classes.contains("ps-6"));
assert!(result.classes.contains("pe-10"));
}
#[test]
fn test_logical_properties_block_directions() {
let classes = ClassBuilder::new()
.margin_block_start(SpacingValue::Integer(4))
.margin_block_end(SpacingValue::Integer(4))
.padding_block_start(SpacingValue::Integer(2))
.padding_block_end(SpacingValue::Integer(2));
let result = classes.build();
assert!(result.classes.contains("mt-4"));
assert!(result.classes.contains("mb-4"));
assert!(result.classes.contains("pt-2"));
assert!(result.classes.contains("pb-2"));
}
#[test]
fn test_logical_properties_inset() {
let classes = ClassBuilder::new()
.inset_inline_start(SpacingValue::Integer(4))
.inset_inline_end(SpacingValue::Integer(4))
.inset_block_start(SpacingValue::Integer(2))
.inset_block_end(SpacingValue::Integer(2));
let result = classes.build();
assert!(result.classes.contains("start-4"));
assert!(result.classes.contains("end-4"));
assert!(result.classes.contains("top-2"));
assert!(result.classes.contains("bottom-2"));
}
}