♻️ (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
e08c412a36
commit
5ef85154b5
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