Skip to content

fix(icons): make animate prop drive the imperative icon animations - #100

Open
jis3r wants to merge 1 commit into
mainfrom
fix/raf-icons-animate-prop
Open

jis3r wants to merge 1 commit into
mainfrom
fix/raf-icons-animate-prop

Conversation

@jis3r

@jis3r jis3r commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Fixes #99.

Problem
Five icons drive their animation with requestAnimationFrame, started only
from the mouseenter handler, so a parent-set animate prop did nothing:
AudioLines, Bot, Eye, MessageCircleMore, MessageSquareMore. In
Bot and the two message icons the single-flight guard also tested the
animate union, so a parent holding animate={true} blocked the hover path
as well. AudioLines and Bot toggle a class that has no CSS rule behind
it, which is why they looked wired up while doing nothing at all.

Only AudioLines was reported; the other four have the same defect. The
sliders pair was already fixed earlier and is untouched here.

Technical changes

  • trigger each animation from the prop via an untracked effect - untrack
    keeps the effect depending on the prop alone, not on the frame state the
    handlers read, which would otherwise re-fire it every frame
  • guard single-flight animations on the in-flight flag instead of the
    animate union, so a held prop no longer blocks hover
  • AudioLines (continuous loop) starts and settles its loop from the prop,
    and no longer settles back on mouseleave while the prop still asks for
    animation
  • two whole-set tests: every icon must render differently when animate is
    set, and every icon with a requestAnimationFrame loop must move
    geometry (not just toggle a class) both from the prop and on hover

Notes

  • the geometry test is the one that matters: the markup-level test passes on
    the broken code, because a toggled class changes the markup even when no
    CSS backs it. Verified the geometry test fails on all five icons before
    the fix and passes after
  • the imperative set is derived from the source (presence of
    requestAnimationFrame), so a future rAF icon is held to the same
    standard automatically
  • circle-alert, frame and shield-alert also toggle a class with no CSS
    rule, but they animate through inline styles and are not broken; cleaning
    up those dead toggles is left out of this fix
  • suite is 1689 tests; static/r regenerated for the five changed sources

AudioLines, Bot, Eye, MessageCircleMore and MessageSquareMore drive their
animation with requestAnimationFrame, started only from the mouseenter
handler, so a parent-set animate prop did nothing. In Bot and the two
message icons the guard also tested the animate union, which meant a parent
holding animate=true blocked the hover path as well.

Each icon now triggers its animation from the prop via an untracked effect
(untrack keeps the effect depending on the prop alone, not on the frame
state it reads), and the single-flight guards test the in-flight flag
instead of the union. AudioLines, which loops continuously, starts and
settles the loop from the prop and no longer settles back on mouseleave
while the prop still asks for animation.

Two tests cover the whole set: every icon must render differently when
animate is set, and every icon with a requestAnimationFrame loop must move
geometry (not just toggle a class - AudioLines and Bot toggle a class with
no CSS rule behind it, which is why this looked wired up) both from the
prop and on hover.

Fixes #99
@vercel

vercel Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
icons Ready Ready Preview Aug 23, 2026 7:29pm

Request Review

This branch was successfully deployed

1 active deployment
Preview — a48b7653 Deployed Aug 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AudioLines ignores animate prop

1 participant