tdn-logomark
Paquete: @tiendana/utils/logomark
<tdn-logomark> es el logomark vivo en cualquier página: un custom element que reproduce clips, mantiene poses y se adapta a los colourways. Se registra con defineLogomarkElement().
Características
✅ Atributos y propiedades espejo - Cada atributo tiene una propiedad del mismo nombre
✅ play() repite - Reproduce un clip desde el inicio aunque ya sea el actual
✅ Evento ended - Avisa cuando un clip sin bucle termina
✅ Se comporta como un icono - Su caja es la marca; los destellos se desbordan sin mover el layout ni capturar clics
✅ Movimiento reducido - Mantiene la pose estática de cada clip
✅ Se pausa solo - Fuera de pantalla y en pestañas ocultas
Registro
import { defineLogomarkElement } from '@tiendana/utils/logomark';
defineLogomarkElement(); // una vez; no hace nada donde no hay custom elements (render de servidor)
defineLogomarkElement(tag?: string) registra tdn-logomark, o la etiqueta que indiques. Llamarla de nuevo con una etiqueta ya registrada no hace nada. LOGOMARK_TAG exporta el nombre por defecto.
Uso
<tdn-logomark></tdn-logomark> <!-- SMILE, 64 px -->
<tdn-logomark clip="hello" loop size="96" label="Tiendana"></tdn-logomark>
<tdn-logomark still="error" colourway="reverse"></tdn-logomark>
import type { LogomarkEndedEvent } from '@tiendana/utils/logomark';
const mark = document.querySelector('tdn-logomark')!; // tipado como LogomarkElement
mark.addEventListener('ended', event => console.log((event as LogomarkEndedEvent).detail.clip));
mark.play('form-error'); // reproduce de nuevo aunque ya sea el clip
API
Atributos y propiedades
| Atributo / propiedad | Valores | Descripción |
|---|---|---|
clip | un ClipName (ver Clips) | Lo reproduce desde el inicio; loop lo repite. Quitarlo mantiene still. Un nombre desconocido se lee como null |
still | un StillName | La pose que se mantiene mientras no se reproduce ningún clip; SMILE si falta |
loop | booleano | Reinicia el clip al terminar |
colourway | primary (por defecto), reverse, neon, mono, lavender, sun, sky y sus -reverse | Ver Colourways |
size | px CSS | Alto de la marca y lado cuadrado del elemento; 64 por defecto. El width CSS del elemento también funciona |
label | texto | Se anuncia como imagen; sin él el elemento es decorativo y se oculta a la tecnología asistiva |
Las propiedades clip, still y label aceptan null para quitar el atributo; size acepta null para volver al tamaño por CSS.
Métodos
| Método | Descripción |
|---|---|
play(clip, { loop }?) | Reproduce un clip desde el inicio, incluido el que ya se está reproduciendo: un segundo envío fallido vuelve a reproducir form-error. Si pasas loop, actualiza el atributo loop |
refresh() | Relee las propiedades --logomark-* y repinta, tras un cambio de tema de la página |
Eventos
| Evento | Detalle | Descripción |
|---|---|---|
ended | CustomEvent<{ clip: ClipName }> (LogomarkEndedEvent) | Se dispara cuando un clip que no hace bucle llega a su final; con movimiento reducido, de inmediato cuando el clip se inicia con play() o al cambiar clip con el elemento ya conectado |
Interfaz LogomarkElement
export type LogomarkColourway = 'primary' | 'reverse' | 'neon' | 'mono' | 'lavender' | 'lavender-reverse' | 'sun' | 'sun-reverse'
| 'sky' | 'sky-reverse';
export type LogomarkEndedEvent = CustomEvent<{ readonly clip: ClipName }>;
export interface LogomarkElement extends HTMLElement {
clip: ClipName | null;
still: StillName | null;
loop: boolean;
colourway: LogomarkColourway;
size: number | null;
label: string | null;
play(clip: ClipName, options?: { readonly loop?: boolean }): void;
refresh(): void;
}
Tamaño
La caja del elemento es la marca: se maqueta como un icono. Dale tamaño con size (px) o con el width CSS del elemento; la marca se escala con él.
<tdn-logomark size="48"></tdn-logomark>
<tdn-logomark style="width: 3rem"></tdn-logomark>
Los destellos y los pops de los clips se desbordan fuera de la caja, centrados y sin capturar eventos de puntero, así que nunca desplazan el layout ni bloquean un clic.
Accesibilidad
- Sin
label, el elemento es decorativo: queda oculto a la tecnología asistiva (aria-hidden). - Con
label, se expone como imagen (role="img") con ese texto como nombre accesible.
<tdn-logomark label="Tiendana"></tdn-logomark>
Usa label cuando el logomark transmite información por sí solo; déjalo decorativo cuando ya hay texto al lado.
Movimiento reducido
Con prefers-reduced-motion: reduce ningún clip se anima. El elemento mantiene la pose que cada clip representa (por ejemplo congrat mantiene la pose CONGRAT, doze la de dormido, ah el pop) y los clips sin pose propia, como hello o blink, se quedan en SMILE. El evento ended se dispara de inmediato para los clips que se inician con play() o al cambiar clip; el clip presente al conectar el elemento no lo dispara, así que no esperes ended de ese primer clip.
Rendimiento
El elemento se pausa mientras está fuera de pantalla y en una pestaña oculta, y vuelve a pintar al regresar. Se redibuja nítido a la densidad de píxeles del dispositivo.
Plataformas
- HTML
- React 19
- Angular
Con un bundler (Vite, webpack, esbuild...) que resuelva @tiendana/utils/logomark; en HTML sin bundler hace falta un import map que apunte al dist/logomark/index.js servido por tu app.
<script type="module">
import { defineLogomarkElement } from '@tiendana/utils/logomark';
defineLogomarkElement();
</script>
<tdn-logomark clip="hello" label="Tiendana"></tdn-logomark>
React 19 pasa atributos y propiedades a los custom elements tal cual. Los eventos personalizados se escuchan con addEventListener sobre una referencia.
import { useEffect, useRef } from 'react';
import {
defineLogomarkElement,
type ClipName,
type LogomarkColourway,
type LogomarkElement,
type StillName,
} from '@tiendana/utils/logomark';
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'tdn-logomark': React.DetailedHTMLProps<React.HTMLAttributes<LogomarkElement>, LogomarkElement> & {
clip?: ClipName;
still?: StillName;
loop?: boolean;
colourway?: LogomarkColourway;
size?: number;
label?: string;
};
}
}
}
defineLogomarkElement();
export function Saludo({ onEnd }: { onEnd: () => void }) {
const mark = useRef<LogomarkElement>(null);
useEffect(() => {
const el = mark.current;
el?.addEventListener('ended', onEnd);
return () => el?.removeEventListener('ended', onEnd);
}, [onEnd]);
return <tdn-logomark ref={mark} clip="hello" size={48} label="Tiendana" />;
}
El paquete no incluye tipos JSX para la etiqueta, por eso el snippet los declara.
En Angular usa el wrapper tdn-logomark de @tiendana/ngx-core/logomark: inputs de señal para cada atributo, el método play() y el output clipEnd en lugar del evento DOM ended.
Ver También
- Clips - los nombres válidos para
clipystill - Colourways -
colourwayy las propiedades--logomark-* - Canvas propio -
mountLogomark, el elemento sin el elemento - Logomark en Fundamentos - reglas de marca