/** * Sigue al puntero dentro de un elemento y deja su posición en variables CSS. * * Es lo que permite que el reflejo de una tarjeta nazca donde está el cursor en * vez de en un sitio fijo. Sin esto el efecto se nota programado; con esto se * nota material. * * Solo se engancha donde hay puntero fino: en una pantalla táctil no hay nada * que seguir, y escuchar `pointermove` ahí sería gastar batería para nada. * * La lectura de la posición va dentro de un `requestAnimationFrame` porque * `getBoundingClientRect` fuerza al navegador a recalcular la maqueta, y * hacerlo en cada evento de movimiento —que llegan a cientos por segundo— * atasca el desplazamiento de la página. */ export function brillo(nodo: HTMLElement) { if (!matchMedia('(hover: hover) and (pointer: fine)').matches) return; let pendiente = 0; function mover(evento: PointerEvent) { if (pendiente) return; pendiente = requestAnimationFrame(() => { pendiente = 0; const caja = nodo.getBoundingClientRect(); const x = evento.clientX - caja.left; const y = evento.clientY - caja.top; nodo.style.setProperty('--mx', `${x}px`); nodo.style.setProperty('--my', `${y}px`); }); } nodo.addEventListener('pointermove', mover, { passive: true }); return { destroy() { cancelAnimationFrame(pendiente); nodo.removeEventListener('pointermove', mover); } }; }