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.
Centraliza la paginación genérica junto con `Paginated::map_items()`
para enriquecer los elementos de una página con datos de otra tabla sin
perder la metadata de paginación.
Nuevo método `oob()` para incluir fragmentos adicionales marcados con
`hx-swap-oob` en el cuerpo de la respuesta, sin necesidad de construir
el envoltorio a mano ni depender del `hx-target` de la petición.
De paso, `set_header()` usa ya las constantes de `hx::response` en vez
de literales repetidos, y se revisan comentarios.
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.
- Nuevo `SortDir` en `pagetop::html` para representar direcciones de
orden (asc/desc) y calcular la siguiente al pulsar una cabecera.
- `hx_table::sort_link()` construye el enlace de ordenación con los
cuatro atributos `hx-*` fijos, reutilizable en cualquier tabla.
- `HtmxResponse` usa `RoutePath` en `location`/`push_url`/`replace_url`/
`redirect` para preservar "lang"; `location_json()` se separa de
`location()` para el caso de configuración JSON personalizada.
- Añade el módulo `prelude` y una batería de tests para hx, hx_table,
request, response y extension.
`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`.
Amplía también los tipos reexportados (Condition, DbBackend, NotSet,
Order, Set, TransactionError, Unchanged) y habilita el mismo
re-export en migration.rs.
Antes delegaban directamente en `#[tokio::main]`/`#[tokio::test]`; ahora
construyen su propio runtime vía `pagetop::util::build_runtime()`, con
el mismo comportamiento (`Builder::new_multi_thread().enable_all()`).
Las extensiones que usan estas macros ya no necesitan declarar Tokio
como dependencia directa en su `Cargo.toml`.
- 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`.
`Container` y `Kind` pasan a `pagetop::base::component` como componente
genérico reutilizable por cualquier tema. Bootsier conserva `Width` y
añade el *trait* `ContainerBootsier`, que guarda el ancho como valor
extra en `Props`.
Consolida los handlers de estos campos en la capa del tema. Además,
`with_floating_label()` usa un valor extra que lee en `setup()` para
forzar `multiple`/`rows` en 'select` y `textarea`.
Permite sustituir una o varias clases por otras nuevas en una sola
operación, preservando su posición. Adapta el tema Bootsier para usarla
en `Button` y elimina el handler duplicado sin referencias.
- 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.
- Elimina `run_now` y convierte `initialize()` en `async fn`.
- `DBCONN` pasa de `LazyLock` a `OnceLock`; `MigratorBase` adopta
`#[pagetop::async_trait]` con métodos async nativos.
Añade `#[async_trait]` a todos los `impl Extension`, `Theme` y
`Component`. Convierte `prepare()` en `async fn` y añade `.await` a las
llamadas `render()` y `render_offcanvas()`.
`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.
`HttpRequest` vacía `parts.extensions` al extraerse; `Path<T>` y otros
extractores que dependen de ellas deben declararse antes en el handler.
Corregido en el ejemplo hello-name y documentado en HttpRequest.
`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`.
Diferencia el patrón para aplicaciones (activan el motor via *feature*
en su `Cargo.toml`) y extensiones (sin *features*; la selección es
responsabilidad de la aplicación).
- 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.
Sustituye `attrs/` y `classes/` por tres capas diferenciadas:
- `token/`: primitivas CSS (BreakPoint, Color, ScaleSize, etc.).
- `class/`: tipos compuestos (Border, Background, Margin, etc.).
- `bs/*/props.rs`: props tipadas para cada componente de Bootstrap.
El patrón de construcción es `suffix()` -> `push_to()` -> `to_class()`.
`push_to()` es `pub` en `class/` y `bs/*/props.rs` para que los temas
derivados puedan acceder a los mismos mecanismos de construcción.