Añade acciones base y renderizado de componentes

- Añade acciones BeforeRender y AfterRender para ejecutar código
  personalizado antes y después de renderizar un componente.
- Introduce la acción PrepareRender para personalizar totalmente el
  renderizado de un componente.
- Se actualizan las definiciones de acciones para utilizar el nuevo
  "trait" ActionDispatcher.
- Se crea un nuevo trait ComponentTrait para definir componentes
  renderizables.
- Se implementan las estructuras Children y Child para gestionar
  componentes hijos dentro de un componente padre.
- Se añade OptionComponent para encapsular de forma segura componentes
  opcionales y poder usarlos en otros componentes.
This commit is contained in:
Manuel Cillero 2025-07-24 08:38:17 +02:00
parent 36ddbd7ecf
commit 8e67065aae
28 changed files with 1102 additions and 147 deletions

View file

@ -0,0 +1,50 @@
use crate::prelude::*;
use crate::base::action::FnActionWithComponent;
/// Ejecuta [`FnActionWithComponent`] después de que un tema renderice el componente.
pub struct AfterRender<C: ComponentTrait> {
f: FnActionWithComponent<C>,
theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>,
}
/// Filtro para despachar [`FnActionWithComponent`] después de que un tema renderice el componente
/// `C`.
impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> {
/// Devuelve el identificador de tipo ([`UniqueId`]) del tema.
fn theme_type_id(&self) -> Option<UniqueId> {
self.theme_type_id
}
/// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`.
fn referer_type_id(&self) -> Option<UniqueId> {
self.referer_type_id
}
}
impl<C: ComponentTrait> AfterRender<C> {
/// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para
/// un tema dado.
pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self {
AfterRender {
f,
theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()),
}
}
// Despacha las acciones.
#[inline]
pub(crate) fn dispatch(component: &mut C, cx: &mut Context) {
dispatch_actions(
&ActionKey::new(
UniqueId::of::<Self>(),
Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()),
None,
),
|action: &Self| (action.f)(component, cx),
);
}
}

View file

@ -0,0 +1,50 @@
use crate::prelude::*;
use crate::base::action::FnActionWithComponent;
/// Ejecuta [`FnActionWithComponent`] antes de que un tema renderice el componente.
pub struct BeforeRender<C: ComponentTrait> {
f: FnActionWithComponent<C>,
theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>,
}
/// Filtro para despachar [`FnActionWithComponent`] antes de que un tema renderice el componente
/// `C`.
impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> {
/// Devuelve el identificador de tipo ([`UniqueId`]) del tema.
fn theme_type_id(&self) -> Option<UniqueId> {
self.theme_type_id
}
/// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`.
fn referer_type_id(&self) -> Option<UniqueId> {
self.referer_type_id
}
}
impl<C: ComponentTrait> BeforeRender<C> {
/// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para
/// un tema dado.
pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self {
BeforeRender {
f,
theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()),
}
}
// Despacha las acciones.
#[inline]
pub(crate) fn dispatch(component: &mut C, cx: &mut Context) {
dispatch_actions(
&ActionKey::new(
UniqueId::of::<Self>(),
Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()),
None,
),
|action: &Self| (action.f)(component, cx),
);
}
}

View file

@ -0,0 +1,63 @@
use crate::prelude::*;
/// Tipo de función para alterar el renderizado de un componente.
///
/// Permite a un [tema](crate::base::action::theme) sobreescribir el renderizado predeterminado de
/// los componentes.
///
/// Recibe una referencia al componente `component` y una referencia mutable al contexto `cx`.
pub type FnPrepareRender<C> = fn(component: &C, cx: &mut Context) -> PrepareMarkup;
/// Ejecuta [`FnPrepareRender`] para preparar el renderizado de un componente.
///
/// Permite a un tema hacer una implementación nueva del renderizado de un componente.
pub struct PrepareRender<C: ComponentTrait> {
f: FnPrepareRender<C>,
theme_type_id: Option<UniqueId>,
referer_type_id: Option<UniqueId>,
}
/// Filtro para despachar [`FnPrepareRender`] que modifica el renderizado de un componente `C`.
impl<C: ComponentTrait> ActionDispatcher for PrepareRender<C> {
/// Devuelve el identificador de tipo ([`UniqueId`]) del tema.
fn theme_type_id(&self) -> Option<UniqueId> {
self.theme_type_id
}
/// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`.
fn referer_type_id(&self) -> Option<UniqueId> {
self.referer_type_id
}
}
impl<C: ComponentTrait> PrepareRender<C> {
/// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnPrepareRender`] para un
/// tema dado.
pub fn new(theme: ThemeRef, f: FnPrepareRender<C>) -> Self {
PrepareRender {
f,
theme_type_id: Some(theme.type_id()),
referer_type_id: Some(UniqueId::of::<C>()),
}
}
// Despacha las acciones. Se detiene en cuanto una renderiza.
#[inline]
pub(crate) fn dispatch(component: &C, cx: &mut Context) -> PrepareMarkup {
let mut render_component = PrepareMarkup::None;
dispatch_actions(
&ActionKey::new(
UniqueId::of::<Self>(),
Some(cx.theme().type_id()),
Some(UniqueId::of::<C>()),
None,
),
|action: &Self| {
if render_component.is_empty() {
render_component = (action.f)(component, cx);
}
},
);
render_component
}
}