Permite que métodos como `with_color(color: impl IntoColor)` acepten un
color directo o uno opcional (`Some(...)`/`None`) sin la ambigüedad que
produce un `Into<Option<C>>` genérico.
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.
`Attr<T>` no aportaba nada sobre `Option<T>` directo: `Getters` ya trata
los campos `Option<T>` como caso especial (`Option<&T>`, o `Option<T>`
con `#[getters(copy)]`) y `#[builder_fn]` funciona igual sobre ellos.
Como `Theme::parent()` se resuelve en tiempo de ejecución, una
referencia cíclica (en la que un tema acaba siendo padre de sí mismo,
directa o transitivamente) no puede descartarse en compilación. Se
detecta al registrar el tema y aborta el arranque si procede.
Introduce `CoreRegions::Aside` como nueva región de plantilla, entre
Header y Content, y Template ahora envuelve el cuerpo en `div.wrapper`,
omitiendo el renderizado si no hay contenido.
`CoreRegion`, `ReservedRegion` y `CoreTemplate` pasan a plural
(`CoreRegions`, `ReservedRegions`, `CoreTemplates`) para no confundirlos
con otras definiciones, y se amplía la documentación del módulo theme.
Antes, RequestLocale sólo guardaba el LanguageIdentifier ya resuelto,
así que `Context::route()` propagaba siempre la forma canónica en los
enlaces generados ("?lang=en-US"), aunque el usuario hubiera pedido
"?lang=en". Ahora se conserva el valor original de la query junto al
idioma resuelto, y se reutiliza al construir nuevos enlaces mientras
siga siendo válido.
El idioma efectivo para renderizar la petición no cambia: sigue siendo
siempre el LanguageIdentifier canónico soportado por la aplicación.
Sustituye las claves de permiso `&str` sueltas por el trait `Permission`
(clave, etiqueta y grupo), y añade `require_permission()` para cortar un
handler con `ErrorPage::AccessDenied` antes de construir nada.
Para que `require_permission()` pueda fallar sin un `Context` previo,
`ErrorPage` pasa a envolver `Option<HttpRequest>`, `Context::new()`
recibe ahora `HttpRequest` sin `Option`, y se añade `Context::admin()`
para la plantilla de administración.
Los prototipos registrados con `InRegion` se clonaban dos veces por
petición: una al ensamblar la región (`ComponentGlobal::as_child`) y
otra al renderizar (`Child::render`). Ahora sólo se clonan al
renderizar.
Elimina el `RwLock<Box<dyn Component>>` interno ya que ningún punto del
ciclo de renderizado tomaba el write-lock.
De paso, `From<Embed<C>> for Child` pasa a una coerción de puntero sin
clonar, gracias al copy-on-write que ya ofrece `Embed::get_mut()`. Los
doctests en `rust,ignore` pasan a `rust,no_run`, verificados por el
compilador.
- Añade `Route::try_resolve()` y `RoutePath::is_empty()` para omitir
atributos HTML opcionales cuando la ruta resultante está vacía.
- Renombra `Locale::configured_langid()` a `try_langid()` (convención
`try_*` para Option).
- Reordena include_locales! y otros cambios menores.
Introduce Region y Template (`base::component::layout`) para componer el
`<body>` de una página, con captura explícita vía `handle_component()`
en lugar de maquetado implícito:
- `RegionName`/`TemplateName` (`core/theme.rs`) como interfaces de
identidad; `CoreRegion` (`Header`/`Content`/`Footer`) y `CoreTemplate`
(`Standard`/`Admin`) como catálogo por defecto.
- `ReservedRegion` (`PageTop`/`PageBottom`, en `response/page.rs`) queda
fuera de `CoreRegion`. `Page::render()` las renderiza siempre,
envolviendo `Theme::render_page_body()`, con independencia de la
plantilla o el tema activos.
- Elimina `TemplateSource` en `Context`: la plantilla pasa a ser un
`TemplateRef` fijo, sin resolución por tema (ese mecanismo nunca llegó
a implementarse).
- La personalización por tema es por captura (`handle_component()` +
`downcast_ref()`), no por sustituir qué constante se resuelve.
- Corrige referencias obsoletas a `DefaultRegions` por `CoreRegion`.
- Sustituye `tests/theme_template.rs` (API anterior) por
`tests/component_template.rs`, que cubre el patrón de captura con el
API nuevo.
`Route` resuelve URLs sensibles al `Context`/idioma en propiedades de
componentes; `RoutePath` (renombrado desde html/route.rs) es el valor
concreto de ruta + query. `Waypoint` transporta la URL de retorno entre
pantallas de listado/alta/edición vía query string.
Ajusta `Context::route()`, `Redirect` y los componentes que aceptan
rutas para integrarse con el nuevo tipo `Route`.
- Los errores controlados (403, 404, fatales) se renderizan con el tema
activo; un `panic!` no controlado se intercepta con un HTML mínimo y
autónomo, sin depender del tema ni de los componentes.
- Corrige además que `Context::template()` no seguía los cambios de tema
hechos con `with_theme()` después de crear la página.
- Renombra `DefaultRegion(s)`/`DefaultTemplate(s)`, añade
`Theme::admin_template()` y `Page::admin()`, y documenta la creación
de temas e `InRegion` en `core/theme.rs`.
- Reordena campos, variantes y métodos para mayor consistencia interna.
- Añade `extra_or`, `extra_or_default` y `extra_or_else` a `Props`.
- Mejora la documentación y amplía los tests de integración.
Nuevo tipo `Preload` (junto a `StyleSheet` y `JavaScript`) que emite
`<link rel="preload">` con soporte para fuentes, estilos, scripts e
imágenes (WebP y AVIF incluidos). Bootsier lo usa para precargar las
fuentes Source Sans 3 y eliminar el FOUT en la carga inicial.
`prepare()` de `Component`, `render()` de `Region` y `Template`, y la
implementación de `ComponentRender` pasan a ser funciones async. Se
actualizan todos los componentes base, helpers, tests y ejemplos.
`async_trait` se re-exporta desde `pagetop` y se añade al preludio; ya
no es necesario declararlo como dependencia en las extensiones.
`initialize()` es ahora verdaderamente `async` (con `.await`), y
`Application::new()` y `prepare()` pasan también a ser funciones
`async`.
- Nuevo módulo `auth` que exporta `CurrentUser`, `CheckPermission` y
`has_permission()`.
- `Context` y `Page` exponen `current_user()` vía `Contextual`.
- `HttpRequest` accede a extensiones de middleware con `extension<T>()`.
- `Extension` incluye nuevo método `configure_middleware`.
- `try_dispatch_actions` para despachar acciones con control del flujo.
- `configure_service` como `configure_router(Router) -> Router`.
- Macro `static_files_service!` como `serve_static_files!`.
- `ResultPage<M, E>` eliminado; handlers devuelven `Result<M, E>`.
- `ErrorPage` implementa `IntoResponse` en lugar de `ResponseError`.
- Registro con `OnceLock`; eliminados `drop_extensions` y `app.welcome`.
- `Redirect` devuelve `Response`; docs y ejemplos actualizados.
Los métodos `required_id()` y `push_message()` son operaciones de tiempo
de renderizado, no de construcción. Se trasladan como métodos inherentes
de `Context`. También se ajustan los métodos asociados a parámetros.
- `From<T: Component> for ChildOp: with_child()` acepta componentes
directamente sin envolverlos en `Child::with(...)`.
- `From<Child> for ChildOp` para completar las conversiones implícitas.
- Actualiza ejemplos y tests con la nueva API en bootsier y aliner.
- Patrón prototipo en `InRegion`: cada petición recibe clones profundos.
- `ComponentClone` habilita clonar `dyn Component` de forma segura.
- `ChildTyped<C>` renombrado a `Slot<C>`, elimina `ChildTypedOp`.
- `Mutex` en lugar de `Arc<RwLock>` en `Child` y `Slot`.
- `is_renderable` y `setup_before_prepare` reciben `&Context`.
- Nuevos tests para `Children`, `ChildOp` y `Slot`.
Elimina `action::theme` fusionando sus responsabilidades en
`action::component`. Renombra `AlterMarkup` a `TransformMarkup` y
`FnActionAlterMarkup` a `FnActionTransformMarkup`. Simplifica
`ActionKey` y mueve los tipos de función al módulo de componente.
Permite a las extensiones transformar el `Markup` final de un componente
mediante edición de texto. Se despacha como último paso del ciclo de
renderizado.
Añade `Theme::parent()` para declarar jerarquías de herencia entre
temas. Sustituye la acción `PrepareRender<C>` por el método
`Theme::prepare_component()` y la macro `render_component!`.
`prepare_component()` ahora devuelve `Result<Markup, ComponentError>` en
lugar de `Markup`, para que los componentes señalen fallos durante el
renderizado de forma explícita.
`ComponentError` encapsula un mensaje de error y un marcado HTML
alternativo opcional (`fallback`). Si se produce un error, el ciclo de
renderizado registra la traza y muestra el `fallback` en lugar del
componente fallido, sin interrumpir el resto de la página.
Lo mismo aplica a los errores devueltos por la acción `PrepareRender` de
los temas, que siguen el mismo mecanismo.
El nombre anterior era ambiguo (podría referirse a cualquier operación
del contexto); `AssetsOp` describe exactamente lo que hace: operar sobre
los recursos del documento.