Iconos en SolidJS
Todavía no hay un paquete específico para Solid, y puedes prescindir de él. El elemento <glyph-fox> funciona en las plantillas de Solid, y un componente de pocas líneas sobre glyphfox/core te da iconos reactivos y compatibles con tree shaking que se renderizan en el servidor.
Instalación
Instala el paquete base. Todo lo de esta página usa puntos de entrada incluidos en él: glyphfox/web para el elemento, y glyphfox/core con glyphfox/icons/NAME para el componente.
npm install glyphfox
| Aspecto | Elemento glyph-fox | Componente Glyph |
|---|---|---|
| Renderizado | En el navegador, cuando el elemento se actualiza. | En el servidor y en el navegador. |
| Código enviado | El elemento, su motor y los iconos que registres. | El renderizador y los módulos de iconos que importes. |
| Movimiento | Morphs en cada cambio de nombre, disparadores de hover y clic, estados. | Movimiento CSS dentro del SVG: presets y morphs al pasar el cursor. |
| Ideal para | Iconos que reaccionan al usuario. | La mayoría de los iconos de una aplicación. |
El elemento glyph-fox
Registra el elemento una sola vez, en tu archivo de entrada. glyphfox/web registra todos los iconos; para que el bundle se limite a los iconos que enumeres, usa glyphfox/web/element con registerIcons, como se muestra en la guía de web components.
import { render } from 'solid-js/web'; import 'glyphfox/web'; import App from './App'; render(() => <App />, document.getElementById('root'));
Los atributos estáticos se compilan dentro de la plantilla, así que llegan al elemento como atributos y funcionan tal como están escritos:
export function Toolbar() { return ( <div class="toolbar"> <glyph-fox name="settings" size="20" weight="1.5" /> <glyph-fox name="bell" animate="shake" trigger="hover" /> </div> ); }
Con los valores dinámicos es distinto. En los custom elements, Solid asigna las expresiones como propiedades, y <glyph-fox> no tiene propiedades: lee atributos. Antepón a las props dinámicas el espacio de nombres attr: para que Solid asigne el atributo en su lugar.
import { createSignal } from 'solid-js'; export function MenuButton() { const [open, setOpen] = createSignal(false); return ( <button type="button" aria-expanded={open()} aria-label={open() ? 'Close menu' : 'Open menu'} onClick={() => setOpen(!open())} > <glyph-fox attr:name={open() ? 'x' : 'menu'} morph duration="300" /> </button> ); }
El atributo morph hace que el elemento anime cada cambio de name, así que cada vez que la señal alterna se reproduce el morph de menú a cerrar, ajustado a mano. Los eventos no necesitan nada especial: onClick en un elemento padre funciona como siempre, y los disparadores como trigger="click" se gestionan dentro del elemento.
TypeScript
Los tipos JSX de Solid no conocen glyph-fox. Decláralo una vez en un archivo de declaraciones y enumera los atributos que asignas mediante attr: en ExplicitAttributes, la interfaz que Solid lee para ese espacio de nombres.
import 'solid-js'; type GlyphFoxAttributes = { name?: string; size?: string | number; color?: string; weight?: string | number; variant?: 'outline' | 'duotone' | 'solid'; animate?: 'draw' | 'pop' | 'wiggle' | 'spin' | 'pulse' | 'bounce' | 'shake'; trigger?: 'mount' | 'hover' | 'click' | 'state'; morph?: boolean | string; 'morph-to'?: string; duration?: string | number; }; declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'glyph-fox': JSX.HTMLAttributes<HTMLElement> & GlyphFoxAttributes; } interface ExplicitAttributes { name: string; size: string | number; active: boolean | string; } } }
Un pequeño componente Glyph
Para los iconos que no necesitan la interacción integrada en el elemento, renderiza el SVG tú mismo. renderToString de glyphfox/core convierte los datos de un icono en marcado con todas las props compartidas, y cada módulo glyphfox/icons/NAME contiene los datos de un solo icono, así que el bundle solo lleva lo que importas.
import { splitProps } from 'solid-js'; import { renderToString } from 'glyphfox/core'; export function Glyph(props) { const [local, options] = splitProps(props, ['icon', 'class']); return ( <span class={local.class} style={{ display: 'inline-flex', 'line-height': '0' }} innerHTML={renderToString(local.icon, options)} /> ); }
import { Glyph } from './Glyph'; import home from 'glyphfox/icons/home'; import bell from 'glyphfox/icons/bell'; export function Nav(props) { return ( <nav> <a href="/"> <Glyph icon={home} size={20} /> Home </a> <button type="button" aria-label="Notifications"> <Glyph icon={bell} animate="shake" trigger="state" active={props.unread > 0} /> </button> </nav> ); }
El efecto detrás de innerHTML rastrea cada prop que lee renderToString, así que un cambio de active, size o icon reescribe el marcado. El marcado se reemplaza, no se interpola. Para un morph entre dos iconos, usa el elemento o un morph CSS al pasar el cursor con morphTo:
import { Glyph } from './Glyph'; import arrowRight from 'glyphfox/icons/arrow-right'; import chevronRight from 'glyphfox/icons/chevron-right'; export const NextLink = () => ( <a href="/next" class="next"> Next <Glyph icon={arrowRight} morphTo={chevronRight} trigger="hover" /> </a> );
Con glyphfox/core, morphTo acepta datos de iconos, no un nombre: solo toSvg, del punto de entrada principal, resuelve nombres. Un nombre pasado aquí se ignora y el icono se queda quieto. El morph CSS se reproduce mientras el puntero está sobre el svg o sobre su padre directo, que en este componente es el span contenedor.
La sintaxis de nombres (file+check@tr, cloud&lock) también la resuelve toSvg. Con el core, usa en su lugar las props y las funciones auxiliares equivalentes: modifier y modifierCorner para las insignias, fuse para las fusiones.
import { fuse } from 'glyphfox/core'; import { Glyph } from './Glyph'; import file from 'glyphfox/icons/file'; import cloud from 'glyphfox/icons/cloud'; import lock from 'glyphfox/icons/lock'; const secureCloud = fuse([cloud, lock], { layout: 'overlap' }); export const Status = () => ( <p> <Glyph icon={file} modifier="check" modifierCorner="top-right" title="Saved" /> <Glyph icon={secureCloud} size={32} title="Encrypted backup" /> </p> );
SolidStart y renderizado en el servidor
El componente Glyph se renderiza en el servidor como cualquier otro marcado: SolidStart escribe el SVG en el HTML, así que los iconos forman parte del primer pintado y el diseño no se mueve cuando la página se hidrata.
El elemento es una funcionalidad del navegador. Se actualiza después de que se ejecute su script y no usa shadow DOM declarativo, así que el HTML del servidor contiene la etiqueta vacía. Reserva su caja con CSS o usa el componente Glyph para los iconos que deban verse de inmediato. Las ventajas e inconvenientes de cada framework están en renderizado en el servidor.
glyph-fox:not(:defined) { display: inline-block; width: 24px; height: 24px; }
Importar glyphfox/web en el servidor no causa problemas: el elemento comprueba si existe customElements y, si no, no hace nada. Aun así, impórtalo desde código de cliente, como src/entry-client.tsx en SolidStart, para que el elemento y sus iconos queden fuera del bundle del servidor.
Props
El componente Glyph pasa sus props a renderToString, así que acepta las opciones compartidas con sus nombres en camelCase. En el elemento, esas mismas props son atributos en kebab-case, que se detallan en la guía de web components.
| Opción | Tipo | Por defecto | Descripción |
|---|---|---|---|
size | number, string | 24 | Ancho y alto; los números son píxeles. |
color | string | currentColor | Color principal. |
secondaryColor | string | color | Color de la capa duotone y del relleno sólido. |
secondaryOpacity | number | 0.3 / 1 | Opacidad de la capa duotone o del relleno sólido. |
weight | number | 2 | Trazo de 1 a 3 en la cuadrícula de 24, con compensación óptica por debajo de 24 px. |
absoluteWeight | boolean | false | Mantiene el trazo en weight píxeles a cualquier tamaño. |
corners | round, sharp | round | Uniones y extremos redondeados o rectos. |
variant | outline, duotone, solid | outline | Eje de estilo; solid se obtiene de las formas cerradas. |
rotate | number | 0 | Rotación en grados. |
flipX | boolean | false | Refleja en horizontal. |
flipY | boolean | false | Refleja en vertical. |
mirrorRtl | boolean | false | Refleja en layouts de derecha a izquierda. |
animate | draw, pop, wiggle, spin, pulse, bounce, shake | ninguno | Preset de estado vivo. |
trigger | mount, hover, click, state | mount | Cuándo se reproduce la animación o el morph. |
active | boolean | false | El estado para el disparador state. |
duration | number (ms) | según el preset | Duración de la animación o del morph. |
delay | number (ms) | 0 | Retraso de la animación o del morph. |
loop | boolean, number | false | Repite sin fin o un número de veces (spin y pulse se repiten por defecto). |
modifier | plus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dot | ninguno | Insignia con hueco de recorte automático. |
modifierCorner | top-left, top-right, bottom-left, bottom-right | bottom-right | Esquina de la insignia. |
morphTo | name, data | ninguno | Destino del morph; el disparador decide cuándo se muestra. |
title | string | ninguno | Nombre accesible: title, role img y aria-label. |
decorative | boolean | true sin title | Oculta el icono a las tecnologías de apoyo. |
Errores comunes
- Props dinámicas sin attr:
name={...}englyph-foxasigna una propiedad que el elemento ignora, y el icono se renderiza vacío. Escribeattr:name={...}. Las cadenas estáticas funcionan sin el prefijo.- Un nombre en morphTo
renderToStringdel core necesita datos de iconos paramorphTo. Una cadena se ignora. Importa el icono de destino y pasa sus datos.- Las animaciones de montaje se repiten
- Cada cambio de prop reemplaza el
innerHTML, así que un preset con eltrigger="mount"por defecto se vuelve a reproducir. Para animaciones ligadas al estado, usatrigger="state"conactive. - Todos los iconos por accidente
import { toSvg } from 'glyphfox'mete todos los iconos en el bundle, porque un nombre puede apuntar a cualquiera de ellos. En el código de cliente, usa el core con un módulo por icono; reservatoSvgpara el código que solo se ejecuta en el servidor.- El elemento en el servidor
- El HTML del servidor contiene un
<glyph-fox>vacío hasta que se ejecuta el script. Reserva su tamaño o renderiza con el componente Glyph los iconos que deban verse en el HTML del servidor. - El span contenedor
- El componente Glyph envuelve el svg en un span: el gap de flex y de grid se aplica al span, y
classva al span, no al svg. Define los tamaños mediante props en lugar de con CSS en el span.
Preguntas frecuentes
¿Hay un paquete de glyphfox para Solid?
Todavía no. Los dos enfoques de esta página usan lo que el paquete glyphfox ya incluye hoy: el custom element y el renderizador del core sobre el que se construyen los paquetes de React, Vue y Svelte.
¿Los iconos se actualizan cuando cambia una señal?
Sí. Con el elemento, enlaza mediante attr: y el elemento se vuelve a dibujar en cada cambio de atributo, con un morph cuando el atributo morph está presente. Con el componente Glyph, el efecto detrás de innerHTML rastrea las props que lee el renderizador y reescribe el marcado.