diff --git a/web/src/components/UndoToast.test.ts b/web/src/components/UndoToast.test.ts index 3378504..b5a2b30 100644 --- a/web/src/components/UndoToast.test.ts +++ b/web/src/components/UndoToast.test.ts @@ -71,4 +71,19 @@ describe('UndoToast', () => { const w = mount(UndoToast, { props: { action: labelAction } }) expect(w.find('[role="status"]').exists()).toBe(true) }) + + it('emits expire when tick fires with timestamp beyond DURATION', async () => { + let capturedTick: FrameRequestCallback | null = null + vi.stubGlobal('requestAnimationFrame', (fn: FrameRequestCallback) => { + capturedTick = fn + return 1 + }) + vi.spyOn(performance, 'now').mockReturnValue(0) + const w = mount(UndoToast, { props: { action: labelAction } }) + await import('vue').then(v => v.nextTick()) + // Simulate a tick timestamp 6 seconds in — beyond the 5-second DURATION + if (capturedTick) capturedTick(6000) + await import('vue').then(v => v.nextTick()) + expect(w.emitted('expire')).toBeTruthy() + }) }) diff --git a/web/src/components/UndoToast.vue b/web/src/components/UndoToast.vue index 18e7f57..aa02a04 100644 --- a/web/src/components/UndoToast.vue +++ b/web/src/components/UndoToast.vue @@ -13,7 +13,7 @@ import { ref, onMounted, onUnmounted, computed } from 'vue' import type { LastAction } from '../stores/label' const props = defineProps<{ action: LastAction }>() -defineEmits<{ undo: [] }>() +const emit = defineEmits<{ undo: []; expire: [] }>() const DURATION = 5000 const elapsed = ref(0) @@ -30,14 +30,15 @@ const label = computed(() => { }) function tick(ts: number) { - if (!start) start = ts elapsed.value = ts - start if (elapsed.value < DURATION) { raf = requestAnimationFrame(tick) + } else { + emit('expire') } } -onMounted(() => { raf = requestAnimationFrame(tick) }) +onMounted(() => { start = performance.now(); raf = requestAnimationFrame(tick) }) onUnmounted(() => cancelAnimationFrame(raf)) diff --git a/web/src/views/LabelView.vue b/web/src/views/LabelView.vue index 1925bfc..cc7df66 100644 --- a/web/src/views/LabelView.vue +++ b/web/src/views/LabelView.vue @@ -1,11 +1,19 @@