use std::sync::{Arc, RwLock};
use super::typed::TypedClass;
use super::utility::{UtilityClass, UtilityRegistry};
pub struct ClassesBuilder {
classes: Vec<String>,
registry: Arc<RwLock<UtilityRegistry>>,
}
impl ClassesBuilder {
pub fn new() -> Self {
Self {
classes: Vec::new(),
registry: Arc::new(RwLock::new(super::utility::create_default_registry())),
}
}
pub fn with_registry(registry: UtilityRegistry) -> Self {
Self {
classes: Vec::new(),
registry: Arc::new(RwLock::new(registry)),
}
}
pub fn registry(&self) -> Arc<RwLock<UtilityRegistry>> {
Arc::clone(&self.registry)
}
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, class: &str) -> Self {
if !class.is_empty() {
self.classes.push(class.to_string());
}
self
}
pub fn add_if(mut self, class: &str, condition: bool) -> Self {
if condition && !class.is_empty() {
self.classes.push(class.to_string());
}
self
}
pub fn add_all(mut self, classes: &[&str]) -> Self {
for class in classes {
self = self.add(class);
}
self
}
pub fn add_utility(mut self, utility_class: &str) -> Self {
if !utility_class.is_empty() {
let registry = self.registry.read().unwrap();
if registry.find(utility_class).is_some() {
self.classes.push(utility_class.to_string());
}
}
self
}
pub fn add_utility_if(mut self, utility_class: &str, condition: bool) -> Self {
if condition && !utility_class.is_empty() {
let registry = self.registry.read().unwrap();
if registry.find(utility_class).is_some() {
self.classes.push(utility_class.to_string());
}
}
self
}
pub fn add_utility_with_css(mut self, utility_class: &str) -> (Self, Option<String>) {
let css = if utility_class.is_empty() {
None
} else {
let registry = self.registry.read().unwrap();
let css = registry.generate_css(utility_class);
if css.is_some() {
self.classes.push(utility_class.to_string());
}
css
};
(self, css)
}
pub fn generate_css(&self) -> String {
let registry = self.registry.read().unwrap();
let mut css_rules = Vec::new();
for class in &self.classes {
if let Some(css) = registry.generate_css(class) {
css_rules.push(css);
}
}
css_rules.join("\n")
}
pub fn generate_stylesheet(&self) -> String {
let css = self.generate_css();
if css.is_empty() {
String::new()
} else {
format!("/* Utility Classes */\n{}", css)
}
}
pub fn register_utility(self, utility: Arc<dyn UtilityClass>) -> Self {
{
let mut registry = self.registry.write().unwrap();
registry.register(utility);
}
self
}
pub fn build(self) -> String {
self.classes.join(" ")
}
pub fn add_typed<T: TypedClass>(mut self, class: T) -> Self {
for name in class.class_names() {
if !name.is_empty() {
self.classes.push(name.to_string());
}
}
self
}
pub fn add_typed_if<T: TypedClass>(mut self, class: T, condition: bool) -> Self {
if condition {
for name in class.class_names() {
if !name.is_empty() {
self.classes.push(name.to_string());
}
}
}
self
}
pub fn add_typed_all<T: TypedClass>(mut self, classes: &[T]) -> Self {
for class in classes {
for name in class.class_names() {
if !name.is_empty() {
self.classes.push(name.to_string());
}
}
}
self
}
pub fn to_vdom_classes(self) -> tairitsu_vdom::Classes {
let mut classes = tairitsu_vdom::Classes::new();
for class in self.classes {
classes = classes.add(&class);
}
classes
}
}
impl Default for ClassesBuilder {
fn default() -> Self {
Self::new()
}
}
impl From<&str> for ClassesBuilder {
fn from(s: &str) -> Self {
let mut builder = Self::new();
for class in s.split_whitespace() {
builder = builder.add(class);
}
builder
}
}
impl From<String> for ClassesBuilder {
fn from(s: String) -> Self {
Self::from(s.as_str())
}
}
impl ClassesBuilder {
pub fn add_utilities(mut self, classes: &str) -> Self {
let classes_to_add: Vec<String> = {
let registry = self.registry.read().unwrap();
classes
.split_whitespace()
.filter(|class| registry.find(class).is_some())
.map(|s| s.to_string())
.collect()
};
self.classes.extend(classes_to_add);
self
}
pub fn add_utilities_if(mut self, classes: &str, condition: bool) -> Self {
if condition {
let classes_to_add: Vec<String> = {
let registry = self.registry.read().unwrap();
classes
.split_whitespace()
.filter(|class| registry.find(class).is_some())
.map(|s| s.to_string())
.collect()
};
self.classes.extend(classes_to_add);
}
self
}
pub fn from_utilities(classes: &str) -> Self {
Self::new().add_utilities(classes)
}
pub fn add_mixed(mut self, classes: &str) -> Self {
for class in classes.split_whitespace() {
self = self.add(class);
}
self
}
}