diff --git a/frontend/src/lib/completion-motion.ts b/frontend/src/lib/completion-motion.ts index d1c3e6c..73350b2 100644 --- a/frontend/src/lib/completion-motion.ts +++ b/frontend/src/lib/completion-motion.ts @@ -1,6 +1,7 @@ type CompletionId = string type CompletionTimer = number +type CompletionFrame = number export function createCompletionPulse( activate: (id: CompletionId) => void, @@ -8,19 +9,23 @@ export function createCompletionPulse( duration = 420, ) { const timers = new Map() + const frames = new Map() return (id: CompletionId) => { - const previous = timers.get(id) - if (previous !== undefined) { - window.clearTimeout(previous) - deactivate(id) - } - window.requestAnimationFrame(() => { + const previousTimer = timers.get(id) + if (previousTimer !== undefined) window.clearTimeout(previousTimer) + const previousFrame = frames.get(id) + if (previousFrame !== undefined) window.cancelAnimationFrame(previousFrame) + deactivate(id) + + const frame = window.requestAnimationFrame(() => { + frames.delete(id) activate(id) timers.set(id, window.setTimeout(() => { deactivate(id) timers.delete(id) }, duration)) }) + frames.set(id, frame) } } diff --git a/frontend/src/style.test.ts b/frontend/src/style.test.ts index 4d51162..aee17a0 100644 --- a/frontend/src/style.test.ts +++ b/frontend/src/style.test.ts @@ -64,6 +64,7 @@ describe('completion feedback motion', () => { const active = new Set() const pulse = createCompletionPulse((id) => active.add(id), (id) => active.delete(id), 420) pulse('item-1') + pulse('item-1') vi.advanceTimersByTime(16) expect(active.has('item-1')).toBe(true) vi.advanceTimersByTime(200)