Preguntas frecuentes
IDs duplicados al insertar una bandera más de una vez
Cada SVG define ids para su recorte, su degradado y su dibujo. Los ids llevan la bandera y la forma (pn-ar-clip para el banderín, pn-ar-circle-clip para el círculo), así que banderas distintas, o formas distintas de la misma bandera, nunca chocan. Insertar el mismo SVG dos veces sí genera ids repetidos. Los navegadores suelen dibujarlo igual, hasta que la primera copia se oculta con display: none: entonces las demás pierden el recorte y el degradado.
<Pennant>y<PennantSvg>reescriben los ids en cada instancia (pn<scope>-<código>[-<forma>]-, a partir deuseId), así que varias copias, formas o raíces de React nunca comparten ids.<pennant-flag>los mantiene dentro de su shadow root.- Si insertas el SVG a mano con
innerHTML, pasa un prefijo único:renderFlag(ar, { idPrefix: 'hero' })oloadFlag('ar', { shape: 'circle', idPrefix: 'fila-3' }). Un<img>(por ejemplo contoDataUri) también aísla los ids.
Content Security Policy
| Formato | Necesita |
|---|---|
<img>, PNG, clases CSS | img-src con tu dominio o https://cdn.jsdelivr.net |
toDataUri(svg) en <img> o CSS | img-src data: |
| Chunks diferidos | script-src de tu propio origen (son parte de tu bundle) |
| Modo fetch | connect-src para el dominio de base (por defecto https://cdn.jsdelivr.net) |
| SVG inline, React, Web Component, personalización | nada extra: funciona con style-src 'self' |
Ningún formato necesita 'unsafe-inline':
- El SVG de la bandera no tiene atributos
style: los colores de la barra son atributos de presentación y la personalización es una regla depennants/css/theme.css. - En React, los modos inline y fetch y
<PennantSvg>generan un<span role="img">con un<svg width height viewBox>adentro, dimensionado con atributos, así que tampoco necesitan hoja de estilos. <pennant-flag>aplica sus estilos con una hoja de estilos construible (adoptedStyleSheets), que la CSP no restringe. Solo los navegadores sin esa API recurren a un elemento<style>.
Dos casos todavía generan un atributo style, que una style-src estricta bloquea: <Pennant mode="img"> con un size en unidades CSS (usa un número) y cualquier prop style que pases tú.
SSR e hidratación
pennants/reactse puede importar desde React Server Components.<PennantSvg>se renderiza en el servidor;<Pennant>vive en un módulo'use client'y pasa a ser una referencia de cliente.pennants/react/staticexporta solo<PennantSvg>, para bundlers que de otro modo emitirían igual los chunks diferidos.<Pennant>(modo inline) renderiza en el servidor un<svg>vacío del tamaño correcto y carga la bandera después de hidratar. No hay error de hidratación ni salto de layout, pero la bandera no está en el HTML.- Para que la bandera esté en el HTML del servidor, usa
mode="img"o<PennantSvg art={ar} />con un import estático. fetchPennanty el modo fetch funcionan solo en el navegador: necesitanDOMParserpara sanear la respuesta, así que en el servidorfetchPennantrechaza la promesa. Allí usarenderFlagcon un dibujo estático,loadFlago<PennantSvg art>.pennants/elementse puede importar en el servidor:definePennantElementno hace nada donde no existecustomElements. El elemento se dibuja cuando se define en el navegador.getPennantNameusaIntl.DisplayNames. El servidor y el navegador pueden traer versiones distintas de CLDR, así que algún nombre puede variar entre ambos. Si importa, pasa untitleexplícito.
Solo ESM y require
El paquete es solo ESM. Node.js 20.19+ y 22.12+ pueden hacer require() de módulos ES sin top-level await, y este paquete no lo usa:
const { getPennantName } = require('pennants'); // funciona en Node.js 20.19+En entornos más antiguos usa import(). En TypeScript, usa moduleResolution: "bundler", "node16" o "nodenext"; el modo antiguo "node" (node10) no lee exports y no encuentra pennants/react ni pennants/art/*.
Imports de assets en el bundler
Importar un archivo de imagen devuelve lo que tu bundler tenga configurado:
import url from 'pennants/svg/pennant/ar.svg'; // Vite: la URL
import markup from 'pennants/svg/pennant/ar.svg?raw'; // Vite: el SVG como texto- webpack 5: agrega una regla con
type: 'asset/resource'para los.svgdenode_modules/pennants. - Next.js: el import estático de un
.svgdevuelve un objeto; usa.src, la carpeta/publicopennantUrl. pennants/csscon Vite, SvelteKit o Astro: lo más simple esimport 'pennants/css/cdn': las mismas clases, apuntando a URLs de jsDelivr con la versión fijada, que los bundlers no tocan (2,0 kB de CSS con gzip; las banderas se cargan del CDN). Si prefieres servir las banderas tú mismo, usa la hoja de estilos normal y evita que se incrusten. El motivo: Vite incrusta como data URI los assets de menos de 4 KiB, así que la mayoría de las 271 banderas termina dentro de tu CSS: 376,2 kB min /53,0 kB con gzip, en lugar de15,7 kB / 3,8 kB. Para mantenerlas como archivos (enAstro, la opción va dentro devite.build). Next.js y Angular no las incrustan.
// vite.config.js
export default {
build: {
assetsInlineLimit: (file) => (file.includes('/pennants/svg/') ? false : undefined),
},
};Una bandera se ve mal
Los diseños vienen de flag-icons. Revisa primero el repositorio de flag-icons; los problemas del banderín en sí (recorte, barra, tamaños) van en el gestor de issues de pennants.
Falta un código
isPennantCode y codes listan exactamente lo que incluye el paquete. Las banderas nuevas se piden en flag-icons; cuando estén allí, se agregan aquí con la siguiente actualización de flag-icons.