//! Constantes para los atributos y valores de HTMX 2.
//!
//! Usar estas constantes en lugar de literales evita errores tipográficos en tiempo de compilación.
//! Una mala declaración como `"hx-gte"` no genera ningún error en tiempo de ejecución, falla
//! silenciosamente. Con constantes, el compilador lo detecta de inmediato.
//!
//! # Atributos estáticos en `html!`
//!
//! Para valores conocidos en tiempo de compilación, los atributos `hx-*` pueden escribirse
//! directamente en la macro `html!` sin necesidad de [`Props`](pagetop::html::Props):
//!
//! ```rust,no_run
//! use pagetop::prelude::*;
//!
//! let markup = html! {
//!     button hx-get="/api/items" hx-target="#list" hx-swap="outerHTML" { "Load" }
//! };
//! ```
//!
//! # Atributos dinámicos con [`Props`](pagetop::html::Props)
//!
//! Cuando los valores se construyen en tiempo de ejecución o se inyectan desde una extensión,
//! puedes usar [`Props`](pagetop::html::Props) combinado con las constantes de este módulo:
//!
//! ```rust,no_run
//! use pagetop::prelude::*;
//! use pagetop_htmx::prelude::*;
//!
//! let props = Props::new(hx::GET, "/api/items")
//!     .with_prop(PropsOp::set(hx::TARGET, "#list"))
//!     .with_prop(PropsOp::set(hx::SWAP, hx::swap::OUTER_HTML));
//!
//! let markup = html! {
//!     button (props) { "Load" }
//! };
//! ```
//!
//! # Integración en componentes
//!
//! El patrón recomendado es añadir un campo `props: Props` al componente y exponerlo con
//! `with_prop()`. Cualquier extensión puede entonces inyectar atributos HTMX sin que el componente
//! ni el tema necesiten conocer HTMX:
//!
//! ```rust,no_run
//! use pagetop::prelude::*;
//! use pagetop_htmx::prelude::*;
//!
//! #[derive(AutoDefault, Getters)]
//! pub struct MyButton {
//!     props: Props,
//! }
//!
//! impl MyButton {
//!     pub fn new() -> Self { Self::default() }
//!
//!     #[builder_fn]
//!     pub fn with_prop(mut self, op: PropsOp) -> Self {
//!         self.props.alter_prop(op);
//!         self
//!     }
//! }
//!
//! MyButton::new()
//!     .with_prop(PropsOp::set(hx::POST, "/api/save"))
//!     .with_prop(PropsOp::set(hx::TARGET, "#message"))
//!     .with_prop(PropsOp::set(hx::SWAP, hx::swap::INNER_HTML));
//! ```
//!
//! # Eventos en línea
//!
//! Para el atributo `hx-on:*` (cuyo nombre incluye el evento y no puede ser una constante) usa las
//! funciones [`on()`] y [`on_htmx()`]:
//!
//! ```rust,no_run
//! use pagetop::prelude::*;
//! use pagetop_htmx::prelude::*;
//!
//! // Evento nativo del DOM: hx-on:click="..."
//! // Evento propio de HTMX: hx-on::after-swap="..."
//! let props = Props::new(hx::on("click"), "this.classList.toggle('active')")
//!     .with_prop(PropsOp::set(hx::on_htmx("after-swap"), "console.log('done')"));
//! ```

// **< HTTP Methods >*******************************************************************************

/// Realiza una petición GET al servidor y aplica la respuesta al objetivo.
///
/// Es el atributo HTMX más común: carga contenido desde el servidor sin recargar la página.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// let props = Props::new(hx::GET, "/api/search")
///     .with_prop(PropsOp::set(hx::TARGET, "#results"));
/// ```
pub const GET: &str = "hx-get";

/// Realiza una petición POST al servidor.
///
/// Se usa habitualmente para enviar datos de formulario o acciones que modifican el estado del
/// servidor. Para subida de ficheros, combinar con [`ENCODING`] = `"multipart/form-data"`.
pub const POST: &str = "hx-post";

/// Realiza una petición PUT al servidor.
pub const PUT: &str = "hx-put";

/// Realiza una petición PATCH al servidor.
pub const PATCH: &str = "hx-patch";

/// Realiza una petición DELETE al servidor.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// // Al eliminar un elemento, reemplazarlo con respuesta vacía borra el nodo del DOM.
/// let props = Props::new(hx::DELETE, "/api/item/42")
///     .with_prop(PropsOp::set(hx::TARGET, "closest li"))
///     .with_prop(PropsOp::set(hx::SWAP, hx::swap::OUTER_HTML));
/// ```
pub const DELETE: &str = "hx-delete";

// **< Target and Swap >****************************************************************************

/// Selector CSS del elemento que recibirá la respuesta. Por defecto, el elemento mismo.
///
/// Además de selectores CSS estándar, HTMX acepta `"this"` (el elemento), `"closest X"` (ancestro
/// más próximo), `"find X"` (descendiente) y `"next X"` / `"previous X"`.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// let props = Props::new(hx::GET, "/api/detalles")
///     .with_prop(PropsOp::set(hx::TARGET, "closest article"));
/// ```
pub const TARGET: &str = "hx-target";

/// Cómo se inserta la respuesta en el DOM. Por defecto, `innerHTML`.
///
/// Los valores estándar están disponibles en el sub-módulo [`swap`]. Además del modo base, se
/// pueden añadir modificadores separados por espacio: retrasos (`swap:200ms`), tiempo de
/// asentamiento (`settle:300ms`), scroll (`scroll:top`) y foco (`focus-scroll:true`).
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// // Reemplaza el elemento completo con una transición de 300 ms.
/// let props = Props::new(hx::SWAP, "outerHTML swap:300ms");
/// // O usando la constante tipada más los modificadores:
/// let props = Props::new(hx::SWAP, format!("{} swap:300ms", hx::swap::OUTER_HTML));
/// ```
pub const SWAP: &str = "hx-swap";

/// Sustituye fuera de banda el elemento del DOM cuyo `id` coincida con el indicado.
///
/// La respuesta del servidor puede incluir elementos marcados con `hx-swap-oob="true"`: HTMX los
/// extrae y actualiza el DOM en la posición correcta, independientemente del objetivo principal.
pub const SWAP_OOB: &str = "hx-swap-oob";

/// Selector CSS del fragmento de la respuesta que se insertará en el objetivo.
///
/// Permite devolver una página completa desde el servidor y que HTMX extraiga sólo la parte
/// relevante, facilitando la reutilización de rutas existentes.
pub const SELECT: &str = "hx-select";

/// Selector CSS de fragmentos de la respuesta que se sustituyen fuera de banda.
pub const SELECT_OOB: &str = "hx-select-oob";

// **< Trigger >************************************************************************************

/// Evento que activa la petición. Por defecto, `click` en botones y links, `change` en inputs.
///
/// Los valores simples están disponibles en el sub-módulo [`trigger`]. Las expresiones de disparo
/// compuestas se escriben como literales de cadena:
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// // Buscar mientras se escribe, con 400 ms de espera y sólo si el valor cambia:
/// let props = Props::new(hx::GET, "/api/search")
///     .with_prop(PropsOp::set(hx::TRIGGER, "keyup changed delay:400ms"))
///     .with_prop(PropsOp::set(hx::TARGET, "#results"));
///
/// // Disparar una vez al cargar la página:
/// let lazy = Props::new(hx::GET, "/api/stats")
///     .with_prop(PropsOp::set(hx::TRIGGER, "load once"));
///
/// // Polling cada 5 segundos:
/// let poll = Props::new(hx::GET, "/api/estado")
///     .with_prop(PropsOp::set(hx::TRIGGER, "every 5s"));
/// ```
pub const TRIGGER: &str = "hx-trigger";

/// Convierte en AJAX todos los enlaces y formularios del elemento y sus descendientes.
///
/// El valor debe ser `"true"` o `"false"`. Cuando vale `"true"`, las respuestas se aplican al
/// `<body>` por defecto; se puede combinar con [`TARGET`] para redirigirlas.
pub const BOOST: &str = "hx-boost";

/// Empuja la URL de la respuesta al historial del navegador.
///
/// Acepta `"true"` (usa la URL de la petición), `"false"` (desactiva) o una URL concreta. Permite
/// navegación con el botón atrás manteniendo el comportamiento SPA.
pub const PUSH_URL: &str = "hx-push-url";

/// Reemplaza la URL actual en el historial sin añadir una nueva entrada.
///
/// Acepta `"true"`, `"false"` o una URL concreta. Útil cuando la petición refina la vista sin que
/// deba ser un paso independiente en el historial.
pub const REPLACE_URL: &str = "hx-replace-url";

/// Sincroniza las peticiones del elemento con las de otros elementos.
///
/// Formato: `"selector:estrategia"`. Estrategias disponibles: `drop` (descarta la nueva si hay una
/// en curso), `abort` (cancela la nueva), `replace` (cancela la anterior), `queue first|last|all`
/// (encola). Ejemplo: `"#form:abort"`.
pub const SYNC: &str = "hx-sync";

// **< Request Data >*******************************************************************************

/// Selector CSS de elementos adicionales cuyos valores se incluyen en la petición.
///
/// Acepta selectores CSS estándar más las extensiones de HTMX: `"this"`, `"closest X"`, `"find X"`.
/// Útil para incluir campos de un formulario padre en una petición de detalle.
pub const INCLUDE: &str = "hx-include";

/// Controla qué parámetros del formulario se envían en la petición.
///
/// - `"*"` - todos (valor por defecto).
/// - `"none"` - ninguno.
/// - Lista de nombres: `"name surname"` - sólo esos.
/// - Exclusión: `"not surname"` - todos excepto los indicados.
pub const PARAMS: &str = "hx-params";

/// Valores extra en JSON que se añaden a los parámetros de la petición.
///
/// Formato: objeto JSON. Los valores sobreescriben parámetros del formulario con el mismo nombre.
/// Admite JavaScript con el prefijo `js:`: `"js:{date: new Date().toISOString()}"`.
pub const VALS: &str = "hx-vals";

/// Cabeceras extra en JSON que se añaden a la petición.
///
/// Formato: objeto JSON. Permiten enviar contexto (token de sesión, versión de API, etc.) sin
/// exponerlo en los parámetros visibles del formulario.
pub const HEADERS: &str = "hx-headers";

/// Codificación de la petición. Por defecto, `"application/x-www-form-urlencoded"`.
///
/// Usar `"multipart/form-data"` para peticiones que incluyan campos de tipo `file`.
pub const ENCODING: &str = "hx-encoding";

// **< Element Behavior >***************************************************************************

/// Selector CSS del indicador de carga que se muestra mientras dura la petición.
///
/// El elemento indicado recibe la clase `htmx-request` durante la petición. Por defecto, si no se
/// especifica, la recibe el propio elemento que realiza la petición.
pub const INDICATOR: &str = "hx-indicator";

/// Selector CSS de elementos que se deshabilitan mientras dura la petición.
///
/// Añade el atributo `disabled` durante la petición y lo elimina al terminar. Evita envíos
/// duplicados al hacer clic varias veces.
pub const DISABLED_ELT: &str = "hx-disabled-elt";

/// Muestra un diálogo de confirmación (`window.confirm`) antes de enviar la petición.
///
/// Si el usuario cancela, la petición no se realiza. El valor es el texto del mensaje.
pub const CONFIRM: &str = "hx-confirm";

/// Muestra un `prompt` de texto y envía el resultado como cabecera `HX-Prompt`.
///
/// Si el usuario cancela el prompt, la petición no se realiza.
pub const PROMPT: &str = "hx-prompt";

/// Activa la validación HTML5 del formulario antes de enviar la petición.
///
/// Si algún campo no supera la validación nativa del navegador, la petición se cancela.
pub const VALIDATE: &str = "hx-validate";

/// Preserva el elemento entre respuestas HTMX.
///
/// El elemento debe tener un `id` único. HTMX no lo destruye ni lo recrea al aplicar la respuesta,
/// manteniendo su estado interno (p. ej. posición de reproducción de un vídeo).
pub const PRESERVE: &str = "hx-preserve";

// **< Config and Extensions >**********************************************************************

/// Activa una o varias extensiones HTMX en el elemento y sus descendientes.
///
/// Las extensiones se identifican por nombre y se separan con comas. Extensiones comunes:
/// - `"ws"` - soporte WebSocket.
/// - `"sse"` - soporte Server-Sent Events.
/// - `"json-enc"` - codifica la petición como JSON en lugar de form-urlencoded.
/// - `"loading-states"` - gestión avanzada de estados de carga.
///
/// `pagetop-htmx` sólo integra el *core* de HTMX: usar cualquiera de estas extensiones (ver el
/// [catálogo oficial](https://htmx.org/extensions/)) requiere añadir su script correspondiente por
/// separado, por ejemplo con [`JavaScript::defer()`](pagetop::html::JavaScript::defer) en
/// [`dependencies()`](pagetop::core::extension::Extension::dependencies).
pub const EXT: &str = "hx-ext";

/// Atributos HTMX que los elementos descendientes NO heredarán de este elemento.
///
/// Acepta una lista de atributos separados por comas o `"*"` para bloquear toda herencia.
pub const DISINHERIT: &str = "hx-disinherit";

/// Atributos HTMX que los elementos descendientes SÍ heredarán (anula [`DISINHERIT`]).
pub const INHERIT: &str = "hx-inherit";

/// Opciones de configuración de la petición en JSON.
///
/// Claves disponibles: `timeout` (ms), `credentials` (`"include"`, `"omit"`...), `noHeaders`
/// (bool), `getWithBody` (bool).
pub const REQUEST: &str = "hx-request";

/// Controla si este elemento participa en el historial del navegador.
///
/// Con el valor `"false"`, las peticiones de este elemento no se guardan en el historial aunque
/// [`PUSH_URL`] esté activo en un elemento padre.
pub const HISTORY: &str = "hx-history";

/// Designa el elemento como contenedor del historial del navegador.
///
/// HTMX guarda y restaura el contenido de este elemento al navegar hacia atrás/adelante. Sólo debe
/// haber un elemento con este atributo en la página.
pub const HISTORY_ELT: &str = "hx-history-elt";

/// Desactiva el procesamiento HTMX en el elemento y todos sus descendientes.
///
/// Útil para aislar zonas del DOM gestionadas por otra librería o para desactivar HTMX en secciones
/// de contenido generado dinámicamente donde no debe intervenir.
pub const DISABLE: &str = "hx-disable";

// **< Inline Events (hx-on) >**********************************************************************

/// Genera `hx-on:{event}` para escuchar eventos nativos del DOM en línea.
///
/// Es la alternativa de HTMX a los handlers `on*` de HTML (`onclick`, `onmouseenter`, ...). La
/// diferencia clave está en cómo los trata el navegador bajo una política CSP (*Content Security
/// Policy*): los atributos `on*` son JavaScript en línea y quedan bloqueados si la CSP no incluye
/// `'unsafe-inline'`; en cambio, `hx-on:*` es un atributo de datos que HTMX lee e interpreta desde
/// su propio código ya autorizado, por lo que la CSP no lo bloquea.
///
/// La CSP puede definirla el servidor en la cabecera HTTP `Content-Security-Policy`, o la
/// aplicación en una etiqueta `<meta http-equiv="Content-Security-Policy">` en el `<head>` del
/// documento. En la práctica, pocas aplicaciones configuran una CSP estricta, pero es una buena
/// práctica de seguridad que conviene tener en cuenta.
///
/// El valor es código JavaScript que se ejecuta cuando el evento se dispara; `event` contiene el
/// objeto del evento.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// let props = Props::new(hx::on("click"), "this.classList.toggle('active')")
///     .with_prop(PropsOp::set(hx::on("mouseenter"), "this.style.opacity='0.8'"));
/// ```
pub fn on(event: &str) -> String {
    format!("hx-on:{event}")
}

/// Genera `hx-on::{event}` para escuchar eventos propios de HTMX en línea.
///
/// Los eventos de HTMX usan un doble carácter dos-puntos (`hx-on::evento`). El ciclo de vida
/// completo incluye `before-request`, `after-request`, `before-swap`, `after-swap`,
/// `before-settle`, `after-settle`, `after-on-load`, `history-restore`, entre otros.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// let props = Props::new(hx::on_htmx("before-request"), "console.log('enviando...')")
///     .with_prop(PropsOp::set(hx::on_htmx("after-swap"), "initTooltips()"));
/// ```
pub fn on_htmx(event: &str) -> String {
    format!("hx-on::{event}")
}

// **< HTMX Request Headers >***********************************************************************

/// Nombres de las cabeceras que HTMX envía con cada petición AJAX.
///
/// Están en minúsculas porque así las normaliza el módulo `http`. Se pueden usar con
/// [`HttpRequest::headers()`](pagetop::web::HttpRequest::headers) para leer sus valores
/// directamente, aunque lo habitual es usar el trait
/// [`HtmxRequestExt`](crate::request::HtmxRequestExt).
///
/// ```rust,no_run
/// use pagetop::prelude::*;
/// use pagetop_htmx::prelude::*;
///
/// async fn handler(request: HttpRequest) {
///     if let Some(target) = request.headers().get(hx::request::TARGET) {
///         // El elemento objetivo tenía este id.
///     }
/// }
/// ```
pub mod request {
    /// Siempre `"true"` en peticiones HTMX. Permite distinguirlas de navegaciones directas.
    pub const REQUEST: &str = "hx-request";
    /// `"true"` si la petición viene de un enlace o formulario con `hx-boost`.
    pub const BOOSTED: &str = "hx-boosted";
    /// URL de la página activa en el navegador cuando se realizó la petición.
    pub const CURRENT_URL: &str = "hx-current-url";
    /// `"true"` si la petición es una restauración del historial del navegador.
    pub const HISTORY_RESTORE_REQUEST: &str = "hx-history-restore-request";
    /// Texto introducido por el usuario en un diálogo `hx-prompt`.
    pub const PROMPT: &str = "hx-prompt";
    /// Valor del atributo `id` del elemento objetivo de la petición.
    pub const TARGET: &str = "hx-target";
    /// Valor del atributo `id` del elemento que disparó la petición.
    pub const TRIGGER: &str = "hx-trigger";
    /// Valor del atributo `name` del elemento que disparó la petición.
    pub const TRIGGER_NAME: &str = "hx-trigger-name";
}

// **< HTMX Response Headers >**********************************************************************

/// Cabeceras de respuesta HTTP para HTMX.
///
/// Se pueden usar con [`HeaderMap`](pagetop::web::http::HeaderMap) para construir respuestas
/// manualmente, aunque lo habitual es usar el constructor
/// [`HtmxResponse`](crate::response::HtmxResponse).
///
/// ```rust,no_run
/// use pagetop::prelude::*;
/// use pagetop_htmx::prelude::*;
///
/// let mut headers = web::http::HeaderMap::new();
/// headers.insert(
///     hx::response::TRIGGER.parse::<web::http::HeaderName>().unwrap(),
///     web::http::HeaderValue::from_static("itemAdded"),
/// );
/// ```
pub mod response {
    /// Redirige mediante AJAX a la URL o configuración JSON indicada. Ver
    /// [`HtmxResponse::location()`](crate::response::HtmxResponse::location) y
    /// [`HtmxResponse::location_json()`](crate::response::HtmxResponse::location_json).
    pub const LOCATION: &str = "HX-Location";
    /// Empuja la URL indicada al historial del navegador. Ver
    /// [`HtmxResponse::push_url()`](crate::response::HtmxResponse::push_url).
    pub const PUSH_URL: &str = "HX-Push-Url";
    /// Provoca una redirección completa del navegador. Ver
    /// [`HtmxResponse::redirect()`](crate::response::HtmxResponse::redirect).
    pub const REDIRECT: &str = "HX-Redirect";
    /// Provoca una recarga completa de la página. Ver
    /// [`HtmxResponse::refresh()`](crate::response::HtmxResponse::refresh).
    pub const REFRESH: &str = "HX-Refresh";
    /// Reemplaza la URL actual en el historial. Ver
    /// [`HtmxResponse::replace_url()`](crate::response::HtmxResponse::replace_url).
    pub const REPLACE_URL: &str = "HX-Replace-Url";
    /// Anula el `hx-swap` del elemento. Ver
    /// [`HtmxResponse::reswap()`](crate::response::HtmxResponse::reswap).
    pub const RESWAP: &str = "HX-Reswap";
    /// Anula el `hx-target` del elemento. Ver
    /// [`HtmxResponse::retarget()`](crate::response::HtmxResponse::retarget).
    pub const RETARGET: &str = "HX-Retarget";
    /// Anula el `hx-select` del elemento. Ver
    /// [`HtmxResponse::reselect()`](crate::response::HtmxResponse::reselect).
    pub const RESELECT: &str = "HX-Reselect";
    /// Dispara eventos JavaScript al completar la respuesta. Ver
    /// [`HtmxResponse::trigger()`](crate::response::HtmxResponse::trigger).
    pub const TRIGGER: &str = "HX-Trigger";
    /// Dispara eventos tras la fase *settle*. Ver
    /// [`HtmxResponse::trigger_after_settle()`](crate::response::HtmxResponse::trigger_after_settle).
    pub const TRIGGER_AFTER_SETTLE: &str = "HX-Trigger-After-Settle";
    /// Dispara eventos tras el *swap*. Ver
    /// [`HtmxResponse::trigger_after_swap()`](crate::response::HtmxResponse::trigger_after_swap).
    pub const TRIGGER_AFTER_SWAP: &str = "HX-Trigger-After-Swap";
}

// **< hx-swap Values >*****************************************************************************

/// Valores estándar del atributo [`SWAP`] (`hx-swap`).
///
/// Se pueden combinar con modificadores separados por espacio:
/// - `swap:Xms` - tiempo de espera antes de realizar el intercambio.
/// - `settle:Xms` - tiempo de espera antes de quitar las clases de transición.
/// - `scroll:top` / `scroll:bottom` - desplaza el objetivo tras el intercambio.
/// - `show:top` / `show:bottom` - hace visible el objetivo tras el intercambio.
/// - `focus-scroll:true` - sigue al elemento enfocado.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// // Reemplaza el elemento con una transición de 200 ms y desplaza al inicio:
/// let props = Props::new(hx::SWAP, format!("{} swap:200ms scroll:top", hx::swap::OUTER_HTML));
/// ```
pub mod swap {
    /// Reemplaza el contenido interior del objetivo (valor por defecto de HTMX).
    pub const INNER_HTML: &str = "innerHTML";
    /// Reemplaza el elemento objetivo completo.
    pub const OUTER_HTML: &str = "outerHTML";
    /// Inserta la respuesta antes de la etiqueta de apertura del objetivo.
    pub const BEFORE_BEGIN: &str = "beforebegin";
    /// Inserta la respuesta al inicio del contenido del objetivo.
    pub const AFTER_BEGIN: &str = "afterbegin";
    /// Inserta la respuesta al final del contenido del objetivo.
    pub const BEFORE_END: &str = "beforeend";
    /// Inserta la respuesta después de la etiqueta de cierre del objetivo.
    pub const AFTER_END: &str = "afterend";
    /// Elimina el elemento objetivo independientemente de la respuesta.
    pub const DELETE: &str = "delete";
    /// No realiza ningún intercambio; útil cuando sólo importan las cabeceras de respuesta.
    pub const NONE: &str = "none";
}

// **< hx-trigger Values >**************************************************************************

/// Eventos comunes del atributo [`TRIGGER`] (`hx-trigger`).
///
/// Estos valores cubren los disparadores más simples. Las expresiones de disparo compuestas deben
/// escribirse como literales de cadena. Modificadores disponibles:
/// - `once` - se dispara sólo la primera vez.
/// - `changed` - sólo si el valor del elemento ha cambiado.
/// - `delay:Xms` - espera antes de disparar (se cancela si el evento vuelve a ocurrir).
/// - `throttle:Xms` - limita la frecuencia máxima de disparo.
/// - `from:selector` - escucha el evento en otro elemento.
/// - `target:selector` - sólo si el evento viene del selector indicado.
/// - `consume` - evita que el evento se propague a otros elementos HTMX.
/// - `queue:first|last|all|none` - política de cola cuando llegan eventos consecutivos.
///
/// ```rust,no_run
/// # use pagetop::prelude::*;
/// # use pagetop_htmx::prelude::*;
/// // Búsqueda progresiva: petición 400 ms después de que el usuario deje de escribir.
/// let search = Props::new(hx::TRIGGER, "keyup changed delay:400ms");
///
/// // Carga diferida al entrar en el viewport, una sola vez.
/// let lazy = Props::new(hx::TRIGGER, "intersect once");
///
/// // Polling: actualiza cada 10 segundos mientras el elemento esté en el DOM.
/// let poll = Props::new(hx::TRIGGER, "every 10s");
///
/// // Múltiples eventos: clic o pulsación de Enter en el campo.
/// let multi = Props::new(hx::TRIGGER, "click, keyup[key=='Enter']");
///
/// // Escucha un evento personalizado emitido desde otro elemento.
/// let custom = Props::new(hx::TRIGGER, "itemAdded from:body");
/// ```
pub mod trigger {
    /// Se dispara al hacer clic (valor por defecto en la mayoría de elementos interactivos).
    pub const CLICK: &str = "click";
    /// Se dispara cuando el valor del elemento cambia (valor por defecto en `input`/`select`).
    pub const CHANGE: &str = "change";
    /// Se dispara al enviar un formulario.
    pub const SUBMIT: &str = "submit";
    /// Se dispara al soltar una tecla.
    pub const KEYUP: &str = "keyup";
    /// Se dispara cuando la página termina de cargarse.
    pub const LOAD: &str = "load";
    /// Se dispara cuando el elemento entra en el área visible del *viewport* al hacer scroll.
    pub const REVEALED: &str = "revealed";
    /// Se dispara cuando el elemento intersecta con el *viewport* (Intersection Observer API).
    pub const INTERSECT: &str = "intersect";
}
