JavaScript API
13 módulos Vanilla JS — todos como IIFE, sin dependencias, cada uno con una API window.WB*. Incluidos con una sola etiqueta <script>.
Resumen de módulos
| Módulo | window.* | Métodos principales |
|---|---|---|
| theme.js | WBTheme | setMode, setAccent, setPreset, setRadius, setDensity |
| modal.js | WBModal | open(id), close(id) |
| drawer.js | WBDrawer | open(id), close(id) |
| dropdown.js | WBDropdown | open(el), close(el) |
| tabs.js | WBTabs | activate(tabEl) |
| accordion.js | WBAccordion | open(itemEl), close(itemEl) |
| sidebar.js | WBSidebar | open(), close() |
| nav-group.js | WBNavGroup | open(groupEl), close(groupEl), init() |
| toast.js | WBToast | show(msg, opts), dismiss(toastEl) |
| popover.js | WBPopover | open(wrapperEl), close(wrapperEl), closeAll() |
| tooltip.js | WBTooltip | show(el), hide(el), hideAll() |
| dismiss.js | WBDismiss | dismiss(el) |
| command-palette.js | WBCommandPalette | open(id), close(id), register(id, opts) |
| ajax-toggle.js | WBAjaxToggle | handle(checkboxEl) — automático via evento change |
WBTheme
theme.jsGestiona todos los ejes del tema — establece atributos data-* en <html> y persiste los valores en localStorage.
// Activar modo oscuro
WBTheme.setMode('dark');
// Cambiar color de acento
WBTheme.setAccent('forest');
// Aplicar preset (agrupa radius/shadow/density/font/border)
WBTheme.setPreset('rounded');
// Ajuste fino de ejes individuales
WBTheme.setRadius('sharp');
WBTheme.setDensity('compact');
Disparadores por atributo data (sin JS)
<!-- Ciclo: light → dark → auto --> <button data-wb-mode-cycle>Cambiar modo</button> <!-- Establecer modo específico --> <button data-wb-mode-set="dark">Oscuro</button> <button data-wb-mode-set="light">Claro</button> <button data-wb-mode-set="auto">Auto</button> <!-- Establecer color de acento --> <button data-wb-accent-set="ocean">Ocean</button> <button data-wb-accent-set="forest">Forest</button>
wb-mode, wb-accent, wb-preset, wb-radius, wb-density.
Los valores se restauran automáticamente al cargar la página. Para restablecerlos, elimina estas claves.
WBModal
modal.jsAbre y cierra overlays de diálogo. Gestiona los estados is-open/is-leaving, bloqueo del scroll, tecla Escape y clic en el fondo.
WBModal.open('my-modal');
WBModal.close('my-modal');
Disparadores por atributo data
<!-- Abrir --> <button data-wb-toggle="modal" data-wb-target="#my-modal">Abrir</button> <!-- Cerrar (dentro del modal) --> <button data-wb-dismiss="modal">Cerrar</button> <div class="wb-modal-backdrop" data-wb-dismiss="modal"></div>
Diálogo de confirmación (wb-confirm)
<div class="wb-modal wb-confirm" id="confirm-delete">
<div class="wb-modal-backdrop" data-wb-dismiss="modal"></div>
<div class="wb-modal-dialog">
<div class="wb-confirm-icon wb-confirm-danger">!</div>
<h4 class="wb-confirm-title">¿Eliminar registro?</h4>
<p class="wb-confirm-desc">Esta acción no se puede deshacer.</p>
<div class="wb-confirm-actions">
<button class="wb-btn wb-btn-ghost" data-wb-dismiss="modal">Cancelar</button>
<button class="wb-btn wb-btn-danger" id="confirm-btn">Eliminar</button>
</div>
</div>
</div>
WBDrawer
drawer.jsPanel lateral deslizante con trampa de foco completa. Teclado: Escape cierra; Tab cicla dentro del panel.
WBDrawer.open('my-drawer');
WBDrawer.close('my-drawer');
Disparadores por atributo data
<button data-wb-toggle="drawer" data-wb-target="#my-drawer">Abrir</button> <button data-wb-dismiss="drawer">Cerrar</button>
WBDropdown
dropdown.jsAlterna is-open en un wrapper wb-dropdown. Cierra al hacer clic fuera y con Escape.
var wrapper = document.querySelector('.wb-dropdown');
WBDropdown.open(wrapper);
WBDropdown.close(wrapper);
Disparadores por atributo data
<div class="wb-dropdown"> <button data-wb-toggle="dropdown">Abrir menú</button> <div class="wb-dropdown-menu">...</div> </div>
WBTabs
tabs.jsActiva elementos de pestaña y sus paneles correspondientes.
var tab = document.querySelector('[data-wb-tab="tab2"]');
WBTabs.activate(tab);
Estructura HTML
<div class="wb-tabs">
<div class="wb-tab-list">
<button class="wb-tab-item is-active" data-wb-tab="panel1">Tab 1</button>
<button class="wb-tab-item" data-wb-tab="panel2">Tab 2</button>
</div>
<div class="wb-tab-panels">
<div class="wb-tab-panel is-active" id="panel1">Contenido 1</div>
<div class="wb-tab-panel" id="panel2">Contenido 2</div>
</div>
</div>
WBAccordion
accordion.jsAlterna is-open en elementos de acordeón. Los clics en wb-accordion-trigger se conectan automáticamente.
var item = document.querySelector('.wb-accordion-item');
WBAccordion.open(item);
WBAccordion.close(item);
WBSidebar
sidebar.jsAbre y cierra el overlay de sidebar móvil. Añade/elimina is-open en .wb-sidebar y .wb-dashboard-shell.
WBSidebar.open(); WBSidebar.close();
Disparadores por atributo data
<button data-wb-toggle="sidebar">☰ Menú</button>
WBToast
toast.jsMuestra notificaciones toast de forma programática. Crea el contenedor automáticamente en la primera llamada.
Opciones
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
| type | string | 'default' | 'default' · 'success' · 'error' · 'warning' · 'info' |
| duration | number | 4000 | Retraso antes del cierre automático en ms. 0 = desactivado. |
| position | string | 'top-right' | 'top-right' · 'top-center' · 'top-left' · 'bottom-center' · 'bottom-left' |
| dismissible | boolean | true | Mostrar botón de cierre en el toast |
// Simple
WBToast.show('Configuración guardada.');
// Con tipo
WBToast.show('¡Registro eliminado!', { type: 'success' });
WBToast.show('Error al subir.', { type: 'error' });
// Duración personalizada + posición
WBToast.show('Procesando…', {
type: 'info',
duration: 0, // permanece hasta cerrar manualmente
position: 'bottom-center'
});
// Cierre programático
var toast = WBToast.show('Mensaje largo');
WBToast.dismiss(toast);
WBPopover
popover.jsAlterna is-open en un wb-popover-wrapper. Cierra al hacer clic fuera y con Escape.
<div class="wb-popover-wrapper">
<button data-wb-toggle="popover">Clic aquí</button>
<div class="wb-popover wb-popover-top">
<div class="wb-popover-title">Título</div>
<div class="wb-popover-body">Contenido aquí.</div>
</div>
</div>
<!-- Posiciones: wb-popover-top / -right / -bottom / -left -->
WBTooltip
tooltip.jsMuestra/oculta tooltips definidos via data-wb-tooltip. Se activa al pasar el cursor y al enfocar. Retraso de aparición predeterminado: 300ms.
<!-- HTML -->
<button data-wb-tooltip="Haz clic para guardar"
data-wb-tooltip-placement="top">
Guardar
</button>
<!-- Posiciones: top (predeterminado) / right / bottom / left -->
<!-- JS -->
var el = document.querySelector('[data-wb-tooltip]');
WBTooltip.show(el);
WBTooltip.hide(el);
WBDismiss
dismiss.jsOculta alertas y banners con una animación is-leaving antes de eliminarlos.
<!-- HTML -->
<div class="wb-alert wb-alert-info" id="my-alert">
Texto del mensaje.
<button data-wb-dismiss="alert" class="wb-alert-close">×</button>
</div>
<!-- JS -->
WBDismiss.dismiss(document.getElementById('my-alert'));
El atributo data-wb-dismiss="alert" conecta el cierre automáticamente.
El uso programático es para casos en que se necesita cerrar desde código externo.
WBCommandPalette
command-palette.jsOverlay de paleta de comandos en pantalla completa con navegación por teclado. Se abre con Cmd+K / Ctrl+K.
Opciones
| Opción | Tipo | Descripción |
|---|---|---|
| onSearch | function(query, results) | Se llama en cada pulsación de tecla. Recibe el término de búsqueda y una NodeList filtrada de resultados. |
// Registro simple (búsqueda de texto integrada)
WBCommandPalette.register('#my-cmd');
// Con manejador de búsqueda personalizado
WBCommandPalette.register('#my-cmd', {
onSearch: function(query, results) {
// results es una NodeList de elementos .wb-cmd-result que coinciden con la búsqueda
console.log(query, results.length + ' resultados');
}
});
// Abrir/cerrar programáticamente
WBCommandPalette.open('#my-cmd');
WBCommandPalette.close('#my-cmd');
Atajos de teclado
| Tecla | Acción |
|---|---|
| Cmd/Ctrl+K | Abrir la primera paleta registrada |
| ↑ / ↓ | Navegar por los resultados |
| Enter | Activar el resultado seleccionado |
| Escape | Cerrar la paleta |
WBAjaxToggle
ajax-toggle.jsEnvía una petición AJAX POST cuando una checkbox cambia de estado. Lee el token CSRF del tag meta[name=csrf-token]. Revierte en caso de error y muestra un toast.
Atributos data
| Atributo | Requerido | Descripción |
|---|---|---|
| data-wb-ajax-toggle | Sí | Marca la checkbox para comportamiento AJAX toggle |
| data-wb-url | Sí | URL POST para la petición de toggle |
| data-wb-field | No | Nombre del campo JSON a enviar ({ field: checked }). Predeterminado: value |
| data-wb-success | No | Mensaje toast en caso de éxito |
| data-wb-error | No | Mensaje toast en caso de error (predeterminado: 'Error occurred') |
<!-- HTML -->
<input
type="checkbox"
class="wb-switch"
data-wb-ajax-toggle
data-wb-url="/api/users/42/toggle-active"
data-wb-field="is_active"
data-wb-success="Estado actualizado"
data-wb-error="No se pudo actualizar el estado"
checked
>
<!-- Ejemplo con Laravel Blade -->
<input
type="checkbox"
class="wb-switch"
data-wb-ajax-toggle
data-wb-url="{{ route('users.toggle', $user) }}"
data-wb-field="is_active"
data-wb-success="Estado actualizado"
{{ $user->is_active ? 'checked' : '' }}
>
<!-- Meta tag CSRF (requerido en <head>) -->
<meta name="csrf-token" content="{{ csrf_token() }}">
Formato de la petición
// POST a data-wb-url
// Headers: Content-Type: application/json, X-CSRF-TOKEN: ...
// Body: { "is_active": true }
// En éxito: mostrar WBToast(data-wb-success, { type: 'success' })
// En error: revertir estado de checkbox + WBToast(data-wb-error, { type: 'error' })
Convenciones JS
Patrones comunes usados en todos los módulos.
Clases de estado
| Clase | Uso |
|---|---|
| is-open | El elemento está visible/activo (Modal, Drawer, Dropdown, Sidebar) |
| is-active | Estado seleccionado (Tabs, Nav-Links, Filter-Chips) |
| is-selected | Estado de selección (filas de tabla, elementos de lista) |
| is-leaving | Animación de cierre en curso — se añade antes de eliminar is-open |
Patrón de animación is-leaving
Todas las animaciones de cierre siguen esta secuencia para evitar desapariciones abruptas:
// 1. Añadir is-leaving (activa la transición CSS de cierre)
element.classList.add('is-leaving');
// 2. Esperar a transitionend (con fallback de 300ms)
element.addEventListener('transitionend', function handler() {
element.classList.remove('is-open', 'is-leaving');
element.removeEventListener('transitionend', handler);
}, { once: true });
// Fallback si transitionend no se dispara
setTimeout(function() {
element.classList.remove('is-open', 'is-leaving');
}, 300);
Conexión universal por atributo data
<!-- Abrir cualquier componente togglable -->
<button data-wb-toggle="modal|drawer|dropdown|sidebar|cmd"
data-wb-target="#target-id">Abrir</button>
<!-- Cerrar desde dentro -->
<button data-wb-dismiss="modal|drawer|alert">Cerrar</button>
(function(){ 'use strict'; … })() —
y exponen su API en window.
No hay contaminación del espacio de nombres global; cada módulo es completamente autónomo.