Eventos del componente

Eventos DOM que emite component-limbo, con su target, su burbujeo y las claves de detail.

📡 Cómo se emiten

Todos son CustomEvent con el nombre limbo: seguido del evento, y llevan los datos en event.detail.

  • Eventos de instancia: se disparan en el contenedor de la instancia o, si no hay contenedor (modal), en document. Llevan bubbles: true y cancelable: true, así que escuchar en document sirve en ambos casos. Con varias instancias en la página, escucha en el contenedor de cada una.
  • Eventos globales: los emite el gestor de eventos del componente en document y añaden detail.timestamp. Así llegan limbo:cropperCancelled y limbo:cropperError.
  • Callbacks: cada evento de instancia tiene un callback equivalente en Limbo.create({ callbacks }); consulta la configuración.
⚠️

Un mismo evento puede llegar más de una vez

En la versión actual del componente, algunos eventos (por ejemplo limbo:select o limbo:cropsSaved) se emiten desde la instancia y de nuevo desde el gestor global. Si tu listener tiene efectos secundarios, hazlo idempotente o usa el callback de Limbo.create, que se ejecuta una sola vez.

🧩 Eventos de instancia

Todos los eventos de instancia incluyen en detail la propia instance y un timestamp.

Evento Cuándo se emite Callback equivalente Claves de detail
limbo:ready La instancia termina de inicializarse. Ninguno instance, config, timestamp
limbo:select El usuario elige un fichero de la galería. onSelect instance, eventType, instanceId, timestamp, mode, features, assetId, fileName, mime, width, height, master.urlSigned, variants, metadata
limbo:upload Se termina de subir un fichero. onUpload Las mismas claves que limbo:select
limbo:cropsSaved El usuario guarda los recortes. onCropsSaved instance, eventType, instanceId, timestamp, crops (cada uno con name, url, width, height), assetId, localCrops, asset
limbo:cropperComplete Termina el cropper standalone (modo crop-only). onCropperComplete instance, eventType, instanceId, timestamp, crops
limbo:cropperCancelled El usuario cancela el cropper. Se dispara en document. onCropperCancelled assetId, instanceId, timestamp
limbo:cropperError Falla el cropper. Se dispara en document. onCropperError error, assetId, instanceId, timestamp
limbo:error Error general de la instancia. onError instance, error con message, code y timestamp
limbo:close La instancia se cierra. onClose instance, timestamp
limbo:modal:open Se abre el modal de la instancia. onOpen (no está en la referencia de create) instance, mode ('modal'), timestamp
limbo:modal:close Se cierra el modal de la instancia. onClose (el mismo que para limbo:close) instance, mode ('modal'), timestamp

La URL firmada de un fichero seleccionado o subido está en detail.master.urlSigned, no en una clave url de primer nivel.

🔄 Eventos de AutoInputs

Se disparan en el propio input y burbujean, de modo que también puedes escucharlos en document.

Evento Cuándo se emite Claves de detail
limbo:resultReady La selección termina y el valor ya está listo (y asignado al input si autoAssign está activo). imageData, input, value, config, assignment, legacy
limbo:imageSelected Evento anterior, mantenido por compatibilidad. Usa limbo:resultReady en código nuevo. imageData, input, value, config, formatted
limbo:error Falla el procesado de la selección. error (el mensaje, como string), input, imageData, config

El nombre limbo:error lo usan también las instancias; allí detail.error es un objeto. Distínguelos por el target o por la presencia de detail.input.

🧱 Web component limbo-selector

Elemento personalizado pensado para editores de páginas y frameworks como Vue 3. Se registra solo al cargar el componente en el navegador, y dibuja un botón que abre el selector de Limbo.

Atributo Descripción
accept Tipos permitidos con la sintaxis de accept de HTML. Sin él, acepta cualquier tipo.
return-format url (por defecto), json o assetId.
has-file Booleano: ya hay un fichero seleccionado, el botón muestra «Cambiar».
existing-url URL del fichero ya seleccionado; se usa como imagen inicial al abrir.
disabled, compact Booleanos: deshabilita el botón / usa un tamaño reducido.
label-select, label-change Textos del botón sin fichero / con fichero.
button-class Clase CSS adicional para el botón.
mandatory-crops Array JSON de recortes obligatorios.
public-key Clave pública del portal; alternativa a llamar a Limbo.configure().
token JWT para el modo manual.
auth-mode session o manual. Por defecto session si hay public-key y manual si hay token.

Emite limbo:change con detail = { data, url } (el payload original de Limbo y la URL extraída), con bubbles y composed a true. Métodos públicos: open(), markSelected(url) y clearSelection().

HTML
<limbo-selector accept="image/*" return-format="url" public-key="pk_tu_clave_publica"></limbo-selector>

<script>
    document.querySelector('limbo-selector').addEventListener('limbo:change', (e) => {
        console.log('Seleccionado:', e.detail.url);
    });
</script>

En Vue 3, declara el elemento como personalizado para que no intente resolverlo como componente:

JavaScript
app.config.compilerOptions.isCustomElement = (tag) => tag === 'limbo-selector';

🗂️ Eventos de variantes

Se disparan en document desde el gestor de variantes de una imagen.

Evento Cuándo se emite Claves de detail
limbo:variantDeleted Se elimina una variante. assetId, variantId
limbo:variantsCleared Se han eliminado todas las variantes de la imagen en la sesión. assetId

🧪 Ejemplo

JavaScript
// Fichero seleccionado (en document sirve para cualquier instancia)
document.addEventListener('limbo:select', (e) => {
    console.log('Asset:', e.detail.assetId, e.detail.master?.urlSigned);
});

// Recortes guardados en una instancia concreta
document.querySelector('#banner-selector').addEventListener('limbo:cropsSaved', (e) => {
    e.detail.crops.forEach((crop) => {
        console.log(crop.name, crop.url, crop.width, crop.height);
    });
});

// Resultado de un input con AutoInputs
const input = document.querySelector('input[name="avatar"]');
input.addEventListener('limbo:resultReady', (e) => {
    console.log('Valor del input:', e.detail.value);
});

🚀 Próximos Pasos