✨ (theme): Añade ColorName y CoreColors
Nuevo trait `ColorName` para que cada tema aporte su propia paleta de colores; `CoreColors` es la paleta por defecto. Aprovecha para refactorizar `core/theme.rs` en submódulos por concepto.
This commit is contained in:
parent
1453764462
commit
bb6855e41f
5 changed files with 331 additions and 286 deletions
|
|
@ -195,8 +195,9 @@ pub trait Theme: Extension + Send + Sync {
|
|||
/// - `Some(Ok(markup))` con el HTML generado por el tema para el componente.
|
||||
/// - `Some(Err(e))` si el tema intentó renderizarlo pero falló.
|
||||
///
|
||||
/// Para renderizar usa [`render_component!`], que devuelve `None` si ningún tipo coincide. Para
|
||||
/// mutar sin renderizar usa [`setup_component!`] y devuelve `None` explícitamente:
|
||||
/// Para renderizar usa [`render_component!`](crate::render_component), que devuelve `None` si
|
||||
/// ningún tipo coincide. Para mutar sin renderizar usa
|
||||
/// [`setup_component!`](crate::setup_component) y devuelve `None` explícitamente:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// fn handle_component(
|
||||
|
|
@ -330,3 +331,106 @@ pub trait Theme: Extension + Send + Sync {
|
|||
|
||||
/// Referencia estática a un tema.
|
||||
pub type ThemeRef = &'static dyn Theme;
|
||||
|
||||
// **< render_component! >**************************************************************************
|
||||
|
||||
/// Sobrescribe el renderizado de componentes en [`Theme::handle_component()`].
|
||||
///
|
||||
/// Evalúa `$component` contra cada tipo de componente listado en orden. En cuanto encuentra
|
||||
/// coincidencia, devuelve `Some(Ok(markup))` o `Some(Err(e))` según el resultado de la expresión
|
||||
/// asociada. Si ningún tipo coincide, devuelve `None` para que el sistema continúe con la cadena de
|
||||
/// herencia o con el renderizado por defecto del propio componente.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// fn handle_component(
|
||||
/// &self,
|
||||
/// component: &dyn Component,
|
||||
/// cx: &mut Context,
|
||||
/// ) -> Option<Result<Markup, ComponentError>> {
|
||||
/// render_component!(component, {
|
||||
/// Button => |btn| { Ok(html! { button.btn.btn-primary { (btn.label()) } }) },
|
||||
/// Heading => |h| self.render_heading(h, cx),
|
||||
/// })
|
||||
/// }
|
||||
///
|
||||
/// fn render_heading(&self, h: &Heading, cx: &mut Context) -> Result<Markup, ComponentError> {
|
||||
/// Ok(html! { h2.display-4 { (h.text()) } })
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! render_component {
|
||||
($component:expr, { $($type:ty => |$var:ident| $body:expr),* $(,)? }) => {
|
||||
'render_component: {
|
||||
// Reborrow explícito como referencia compartida para que `downcast_ref` funcione
|
||||
// correctamente con `&mut dyn Component` (limitación del compilador con trait objects).
|
||||
let __c = &*($component);
|
||||
$(
|
||||
if let Some($var) = __c.downcast_ref::<$type>() {
|
||||
break 'render_component Some($body);
|
||||
}
|
||||
)*
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// **< setup_component! >***************************************************************************
|
||||
|
||||
/// Muta un componente dentro de [`Theme::handle_component()`].
|
||||
///
|
||||
/// Evalúa `$component` contra cada tipo de componente listado en orden. En cuanto encuentra
|
||||
/// coincidencia, ejecuta el bloque asociado y detiene la evaluación. Si ningún tipo coincide, no
|
||||
/// hace nada.
|
||||
///
|
||||
/// Usa acceso mutable al componente mediante [`downcast_mut`](crate::core::AnyCast::downcast_mut),
|
||||
/// lo que permite modificar su estado. El tema puede devolver `None` tras la mutación para que otro
|
||||
/// nivel de la cadena se encargue del renderizado.
|
||||
///
|
||||
/// # Ejemplos
|
||||
///
|
||||
/// Solo mutación: el tema ajusta el componente y delega el renderizado al siguiente nivel:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// fn handle_component(
|
||||
/// &self,
|
||||
/// component: &mut dyn Component,
|
||||
/// cx: &mut Context,
|
||||
/// ) -> Option<Result<Markup, ComponentError>> {
|
||||
/// setup_component!(component, { Button => |btn| { btn.add_class("btn-primary"); } });
|
||||
/// None
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Mutación y renderizado combinados: el `Button` se muta y se renderiza aquí; el `Heading` se
|
||||
/// muta pero continúa la cadena para que otro nivel lo renderice:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// fn handle_component(
|
||||
/// &self,
|
||||
/// component: &mut dyn Component,
|
||||
/// cx: &mut Context,
|
||||
/// ) -> Option<Result<Markup, ComponentError>> {
|
||||
/// setup_component!(component, {
|
||||
/// Button => |btn| { btn.add_class("btn-primary"); },
|
||||
/// Heading => |h| { h.add_class("display-4"); },
|
||||
/// });
|
||||
/// render_component!(component, {
|
||||
/// Button => |btn| Ok(html! { button.btn { (btn.label()) } }),
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! setup_component {
|
||||
($component:expr, { $($type:ty => |$var:ident| $body:expr),* $(,)? }) => {
|
||||
'setup_component: {
|
||||
$(
|
||||
if let Some($var) = ($component).downcast_mut::<$type>() {
|
||||
$body;
|
||||
break 'setup_component;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue