♻️ [html] Cambia tipos Option... por Attr...
				
					
				
			Renombra los tipos para atributos HTML `Id`, `Name`, `Value` (`String`), `L10n` (`Translate`) y `Classes`. Y mueve `OptionComponent` al *core* de componentes como `TypedSlot`.
This commit is contained in:
		
							parent
							
								
									75eec8bebc
								
							
						
					
					
						commit
						bb34ba5887
					
				
					 17 changed files with 367 additions and 311 deletions
				
			
		| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Operaciones disponibles sobre la lista de clases en [`OptionClasses`].
 | 
			
		||||
/// Operaciones disponibles sobre la lista de clases en [`AttrClasses`].
 | 
			
		||||
pub enum ClassesOp {
 | 
			
		||||
    /// Añade al final (si no existe).
 | 
			
		||||
    Add,
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ pub enum ClassesOp {
 | 
			
		|||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let classes = OptionClasses::new("Btn btn-primary")
 | 
			
		||||
/// let classes = AttrClasses::new("Btn btn-primary")
 | 
			
		||||
///     .with_value(ClassesOp::Add, "Active")
 | 
			
		||||
///     .with_value(ClassesOp::Remove, "btn-primary");
 | 
			
		||||
///
 | 
			
		||||
| 
						 | 
				
			
			@ -41,14 +41,14 @@ pub enum ClassesOp {
 | 
			
		|||
/// assert!(classes.contains("active"));
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug)]
 | 
			
		||||
pub struct OptionClasses(Vec<String>);
 | 
			
		||||
pub struct AttrClasses(Vec<String>);
 | 
			
		||||
 | 
			
		||||
impl OptionClasses {
 | 
			
		||||
impl AttrClasses {
 | 
			
		||||
    pub fn new(classes: impl AsRef<str>) -> Self {
 | 
			
		||||
        OptionClasses::default().with_value(ClassesOp::Prepend, classes)
 | 
			
		||||
        AttrClasses::default().with_value(ClassesOp::Prepend, classes)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionClasses BUILDER ***********************************************************************
 | 
			
		||||
    // AttrClasses BUILDER *************************************************************************
 | 
			
		||||
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ impl OptionClasses {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionClasses GETTERS ***********************************************************************
 | 
			
		||||
    // AttrClasses GETTERS *************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuele la cadena de clases, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
							
								
								
									
										63
									
								
								src/html/attr_id.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/html/attr_id.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Identificador normalizado para el atributo `id` o similar de HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Se convierte a minúsculas.
 | 
			
		||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let id = AttrId::new("  main Section ");
 | 
			
		||||
/// assert_eq!(id.as_str(), Some("main_section"));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = AttrId::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct AttrId(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl AttrId {
 | 
			
		||||
    /// Crea un nuevo `AttrId` normalizando el valor.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        AttrId::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrId BUILDER ******************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece un identificador nuevo normalizando el valor.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
 | 
			
		||||
        self.0 = if value.is_empty() { None } else { Some(value) };
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrId GETTERS ******************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el identificador normalizado, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        self.0.as_ref().cloned()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el identificador normalizado (sin clonar), si existe.
 | 
			
		||||
    pub fn as_str(&self) -> Option<&str> {
 | 
			
		||||
        self.0.as_deref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el identificador normalizado (propiedad), si existe.
 | 
			
		||||
    pub fn into_inner(self) -> Option<String> {
 | 
			
		||||
        self.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// `true` si no hay valor.
 | 
			
		||||
    pub fn is_empty(&self) -> bool {
 | 
			
		||||
        self.0.is_none()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ use crate::html::Markup;
 | 
			
		|||
use crate::locale::{L10n, LangId};
 | 
			
		||||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Cadena para traducir al renderizar ([`locale`](crate::locale)).
 | 
			
		||||
/// Texto para [traducir](crate::locale) en atributos HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura.
 | 
			
		||||
///
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ use crate::{builder_fn, AutoDefault};
 | 
			
		|||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// // Traducción por clave en las locales por defecto de PageTop.
 | 
			
		||||
/// let hello = OptionTranslated::new(L10n::l("test-hello-world"));
 | 
			
		||||
/// let hello = AttrL10n::new(L10n::l("test-hello-world"));
 | 
			
		||||
///
 | 
			
		||||
/// // Español disponible.
 | 
			
		||||
/// assert_eq!(
 | 
			
		||||
| 
						 | 
				
			
			@ -31,15 +31,15 @@ use crate::{builder_fn, AutoDefault};
 | 
			
		|||
/// assert_eq!(markup.into_string(), "¡Hola mundo!");
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug)]
 | 
			
		||||
pub struct OptionTranslated(L10n);
 | 
			
		||||
pub struct AttrL10n(L10n);
 | 
			
		||||
 | 
			
		||||
impl OptionTranslated {
 | 
			
		||||
    /// Crea una nueva instancia [`OptionTranslated`].
 | 
			
		||||
impl AttrL10n {
 | 
			
		||||
    /// Crea una nueva instancia `AttrL10n`.
 | 
			
		||||
    pub fn new(value: L10n) -> Self {
 | 
			
		||||
        OptionTranslated(value)
 | 
			
		||||
        AttrL10n(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionTranslated BUILDER ********************************************************************
 | 
			
		||||
    // AttrL10n BUILDER ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece una traducción nueva.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ impl OptionTranslated {
 | 
			
		|||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionTranslated GETTERS ********************************************************************
 | 
			
		||||
    // AttrL10n GETTERS ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve la traducción para `language`, si existe.
 | 
			
		||||
    pub fn using(&self, language: &impl LangId) -> Option<String> {
 | 
			
		||||
							
								
								
									
										63
									
								
								src/html/attr_name.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/html/attr_name.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Nombre normalizado para el atributo `name` o similar de HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Se convierte a minúsculas.
 | 
			
		||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let name = AttrName::new("  DISplay name ");
 | 
			
		||||
/// assert_eq!(name.as_str(), Some("display_name"));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = AttrName::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct AttrName(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl AttrName {
 | 
			
		||||
    /// Crea un nuevo `AttrName` normalizando el valor.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        AttrName::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrName BUILDER ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece un nombre nuevo normalizando el valor.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
 | 
			
		||||
        self.0 = if value.is_empty() { None } else { Some(value) };
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrName GETTERS ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el nombre normalizado, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        self.0.as_ref().cloned()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el nombre normalizado (sin clonar), si existe.
 | 
			
		||||
    pub fn as_str(&self) -> Option<&str> {
 | 
			
		||||
        self.0.as_deref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el nombre normalizado (propiedad), si existe.
 | 
			
		||||
    pub fn into_inner(self) -> Option<String> {
 | 
			
		||||
        self.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// `true` si no hay valor.
 | 
			
		||||
    pub fn is_empty(&self) -> bool {
 | 
			
		||||
        self.0.is_none()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								src/html/attr_value.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/html/attr_value.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Cadena normalizada para renderizar en atributos HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let s = AttrValue::new("  a new string   ");
 | 
			
		||||
/// assert_eq!(s.as_str(), Some("a new string"));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = AttrValue::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct AttrValue(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl AttrValue {
 | 
			
		||||
    /// Crea un nuevo `AttrValue` normalizando el valor.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        AttrValue::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrValue BUILDER ***************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece una cadena nueva normalizando el valor.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim();
 | 
			
		||||
        self.0 = if value.is_empty() {
 | 
			
		||||
            None
 | 
			
		||||
        } else {
 | 
			
		||||
            Some(value.to_owned())
 | 
			
		||||
        };
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AttrValue GETTERS ***************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve la cadena normalizada, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        self.0.as_ref().cloned()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve la cadena normalizada (sin clonar), si existe.
 | 
			
		||||
    pub fn as_str(&self) -> Option<&str> {
 | 
			
		||||
        self.0.as_deref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Devuelve la cadena normalizada (propiedad), si existe.
 | 
			
		||||
    pub fn into_inner(self) -> Option<String> {
 | 
			
		||||
        self.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// `true` si no hay valor.
 | 
			
		||||
    pub fn is_empty(&self) -> bool {
 | 
			
		||||
        self.0.is_none()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,68 +0,0 @@
 | 
			
		|||
use crate::builder_fn;
 | 
			
		||||
use crate::core::component::{Component, Typed};
 | 
			
		||||
use crate::html::{html, Context, Markup};
 | 
			
		||||
 | 
			
		||||
/// Contenedor de componente para incluir en otros componentes.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<Typed<C>>` para incluir un componente de manera segura en otros
 | 
			
		||||
/// componentes, útil para representar estructuras complejas.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust,ignore
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let comp = MyComponent::new();
 | 
			
		||||
/// let opt = OptionComponent::new(comp);
 | 
			
		||||
/// assert!(opt.get().is_some());
 | 
			
		||||
/// ```
 | 
			
		||||
pub struct OptionComponent<C: Component>(Option<Typed<C>>);
 | 
			
		||||
 | 
			
		||||
impl<C: Component> Default for OptionComponent<C> {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        OptionComponent(None)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: Component> OptionComponent<C> {
 | 
			
		||||
    /// Crea un nuevo [`OptionComponent`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// El componente se envuelve automáticamente en un [`Typed`] y se almacena.
 | 
			
		||||
    pub fn new(component: C) -> Self {
 | 
			
		||||
        OptionComponent::default().with_value(Some(component))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionComponent BUILDER *********************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece un componente nuevo, o lo vacía.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, component: Option<C>) -> Self {
 | 
			
		||||
        if let Some(component) = component {
 | 
			
		||||
            self.0 = Some(Typed::with(component));
 | 
			
		||||
        } else {
 | 
			
		||||
            self.0 = None;
 | 
			
		||||
        }
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionComponent GETTERS *********************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el componente, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<Typed<C>> {
 | 
			
		||||
        if let Some(value) = &self.0 {
 | 
			
		||||
            return Some(value.clone());
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Renderiza el componente, si existe.
 | 
			
		||||
    pub fn render(&self, cx: &mut Context) -> Markup {
 | 
			
		||||
        if let Some(component) = &self.0 {
 | 
			
		||||
            component.render(cx)
 | 
			
		||||
        } else {
 | 
			
		||||
            html! {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Identificador normalizado para el atributo `id` o similar de HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso.
 | 
			
		||||
///
 | 
			
		||||
/// # Normalización
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Se convierte a minúsculas.
 | 
			
		||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let id = OptionId::new("  main Section ");
 | 
			
		||||
/// assert_eq!(id.get(), Some(String::from("main_section")));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = OptionId::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct OptionId(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl OptionId {
 | 
			
		||||
    /// Crea un nuevo [`OptionId`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        OptionId::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionId BUILDER ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece un identificador nuevo.
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
 | 
			
		||||
        self.0 = (!value.is_empty()).then_some(value);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionId GETTERS ****************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el identificador, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        if let Some(value) = &self.0 {
 | 
			
		||||
            if !value.is_empty() {
 | 
			
		||||
                return Some(value.to_owned());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Nombre normalizado para el atributo `name` o similar de HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso.
 | 
			
		||||
///
 | 
			
		||||
/// # Normalización
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Se convierte a minúsculas.
 | 
			
		||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let name = OptionName::new("  DISplay name ");
 | 
			
		||||
/// assert_eq!(name.get(), Some(String::from("display_name")));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = OptionName::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct OptionName(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl OptionName {
 | 
			
		||||
    /// Crea un nuevo [`OptionName`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        OptionName::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionName BUILDER **************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece un nombre nuevo.
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
 | 
			
		||||
        self.0 = (!value.is_empty()).then_some(value);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionName GETTERS **************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve el nombre, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        if let Some(value) = &self.0 {
 | 
			
		||||
            if !value.is_empty() {
 | 
			
		||||
                return Some(value.to_owned());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,57 +0,0 @@
 | 
			
		|||
use crate::{builder_fn, AutoDefault};
 | 
			
		||||
 | 
			
		||||
/// Cadena normalizada para renderizar en atributos HTML.
 | 
			
		||||
///
 | 
			
		||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso.
 | 
			
		||||
///
 | 
			
		||||
/// # Normalización
 | 
			
		||||
///
 | 
			
		||||
/// - Se eliminan los espacios al principio y al final.
 | 
			
		||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
 | 
			
		||||
///
 | 
			
		||||
/// # Ejemplo
 | 
			
		||||
///
 | 
			
		||||
/// ```rust
 | 
			
		||||
/// use pagetop::prelude::*;
 | 
			
		||||
///
 | 
			
		||||
/// let s = OptionString::new("  a new string   ");
 | 
			
		||||
/// assert_eq!(s.get(), Some(String::from("a new string")));
 | 
			
		||||
///
 | 
			
		||||
/// let empty = OptionString::default();
 | 
			
		||||
/// assert_eq!(empty.get(), None);
 | 
			
		||||
/// ```
 | 
			
		||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
 | 
			
		||||
pub struct OptionString(Option<String>);
 | 
			
		||||
 | 
			
		||||
impl OptionString {
 | 
			
		||||
    /// Crea un nuevo [`OptionString`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    pub fn new(value: impl AsRef<str>) -> Self {
 | 
			
		||||
        OptionString::default().with_value(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionString BUILDER ************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Establece una cadena nueva.
 | 
			
		||||
    ///
 | 
			
		||||
    /// El valor se normaliza automáticamente.
 | 
			
		||||
    #[builder_fn]
 | 
			
		||||
    pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
 | 
			
		||||
        let value = value.as_ref().trim().to_owned();
 | 
			
		||||
        self.0 = (!value.is_empty()).then_some(value);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OptionString GETTERS ************************************************************************
 | 
			
		||||
 | 
			
		||||
    /// Devuelve la cadena, si existe.
 | 
			
		||||
    pub fn get(&self) -> Option<String> {
 | 
			
		||||
        if let Some(value) = &self.0 {
 | 
			
		||||
            if !value.is_empty() {
 | 
			
		||||
                return Some(value.to_owned());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue