Theming
El widget se personaliza con dos mecanismos complementarios:
- Variables CSS
--nrn-*dentro del Shadow DOM — ~30 tokens en categoríassurface,text,border,primary,secondary,accent,radius,shadow,transition,z-indexylayout. StyleOverridesdesde la configuración (config.styles) — sobre-escribe cualquier subconjunto de las variables. Acepta hex (#06b6d4), rgb (rgb(6 182 212)) o RGB-triplet (6 182 212).
Como el widget vive en un Shadow DOM, los estilos del host no entran y los del widget no salen. Esto es deliberado: garantiza paridad visual entre tiendas y elimina conflictos con frameworks CSS del host (Bootstrap, Tailwind del tema, etc.).
Formato RGB-triplet
El widget guarda los colores en el formato R G B (sin coma) para permitir composición con rgb y alpha runtime:
:host, .neuroon-widget {
--nrn-primary: 6 182 212; /* cyan-500 */
--nrn-surface-base: 255 255 255; /* white */
}
.button {
background-color: rgb(var(--nrn-primary));
/* alpha dinámico sin tener que redeclarar el color */
box-shadow: 0 0 0 4px rgb(var(--nrn-primary) / 0.18);
}
Si pasas un hex (#06b6d4) en StyleOverrides, el widget lo convierte automáticamente al formato RGB-triplet.
Override por tema
styles acepta un objeto plano (mismos valores para ambos temas) o uno por tema:
NeuroonWidget.init({
styles: {
light: {
primary: '#06b6d4',
surfaceBase: '#ffffff',
textPrimary: '#0f172a',
},
dark: {
primary: '#22d3ee',
surfaceBase: '#0f172a',
textPrimary: '#f8fafc',
},
},
})
También puedes pasar un solo objeto para aplicar los mismos overrides independientemente del tema:
NeuroonWidget.init({
styles: {
primary: '#0f766e',
radiusLg: '0.5rem',
},
})
En caliente, widget.setStyles({...}) actualiza los estilos sin re-montar el árbol.
widget.setStyles()aceptaStyleOverrides(objeto plano). Si pasas{ light: {...}, dark: {...} }, funciona en runtime pero el tipo de TypeScript es más restrictivo.
Categorías de variables
| Categoría | Prefijo | Ejemplos |
|---|---|---|
| Superficies | --nrn-surface-* | surface-base, surface-elevated, surface-overlay, surface-hover |
| Texto | --nrn-text-* | text-primary, text-secondary, text-muted, text-disabled |
| Bordes | --nrn-border-* | border-default, border-emphasis, border-subtle |
| Marca primaria | --nrn-primary* | primary, primary-light, primary-dark |
| Marca secundaria | --nrn-secondary* | secondary, secondary-light, secondary-dark |
| Accent | --nrn-accent-* | accent-purple, accent-emerald, accent-amber |
| Semánticas | — | --nrn-success, --nrn-error, --nrn-warning |
| Tipografía | --nrn-font-* | font-family, font-size-{xs..2xl} |
| Spacing | --nrn-spacing-* | xs, sm, md, lg, xl |
| Radius | --nrn-radius-* | sm, md, lg, xl, 2xl, full |
| Shadow | --nrn-shadow-* | sm, md, lg, xl |
| Transición | --nrn-transition-* | fast, base, slow |
| Z-index | --nrn-z-* | dropdown, sticky, modal-backdrop, modal, tooltip |
| Layout | — | --nrn-container-max-width, --nrn-drawer-width, --nrn-dropdown-max-height… |
Tabla exhaustiva con defaults light/dark en Reference → Variables CSS. Mapping
StyleOverrides → CSS vardefinido.
Ejemplo end-to-end
const widget = window.NeuroonWidget.init({
container: '#neuroon-search',
token: 'WIDGET_TOKEN',
theme: 'auto',
styles: {
primary: '#0f766e',
primaryLight: '#14b8a6',
radiusLg: '0.5rem',
},
})
widget.setStyles({ primary: '#0891b2' })
Detección automática del host (theme: 'auto')
Con theme: 'auto' (default), el widget consulta window.matchMedia('(prefers-color-scheme: dark)') al montarse y se suscribe a sus cambios. Cada cambio dispara internamente un CustomEvent('neuroon-theme-change') que re-inyecta los overrides.
Forzar tema desde el host
Si el host quiere imponer el tema (p. ej. WooCommerce admin con preview), envía un postMessage:
const iframe = document.querySelector('iframe.neuroon-preview')
iframe.contentWindow.postMessage({
type: 'neuroon:setTheme',
theme: 'dark', // 'light' | 'dark' | 'auto'
}, '*')
Próximas lecturas
- Reference → Variables CSS — tabla exhaustiva con defaults.
- Configuración — formato
StyleOverrides. - Eventos del widget —
neuroon-theme-changeyneuroon:setTheme.