fix(dev-mode): use animationend for modal scroll lock#1140
fix(dev-mode): use animationend for modal scroll lock#1140AdeshDeshmukh wants to merge 1 commit intokitops-ml:mainfrom
Conversation
Replace timer-based body scroll locking with an animationend handler tied to the modalShow animation. This removes timing race conditions and keeps modal behavior robust if animation duration changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the dev-mode Settings modal lifecycle to lock body scrolling based on the modal’s actual CSS animation completion (animationend) instead of a hard-coded mount timer, improving synchronization with the UI transition.
Changes:
- Replaced
setTimeout(150)-based scroll locking inonMountedwith an@animationendhandler. - Removed the now-unused
onMountedimport andisVisiblestate. - Added
onModalAnimationEnd(event: AnimationEvent)to applyoverflow-hiddenwhen the open animation completes.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, 150) | ||
| }) | ||
| const onModalAnimationEnd = (event: AnimationEvent) => { | ||
| if (event.animationName !== 'modalShow' || !isModalOpen.value) { |
There was a problem hiding this comment.
Because this component uses <style scoped>, Vue’s SFC compiler rewrites keyframe names to include a scope hash (e.g., modalShow-xxxx) and updates the animation: declarations accordingly. At runtime event.animationName will likely be the rewritten name, so comparing it to the literal 'modalShow' can prevent the scroll lock from ever being applied. Consider loosening the check (e.g., startsWith('modalShow')), checking event.target === event.currentTarget instead, or moving the @keyframes definition to an unscoped/global style block so the name stays stable.
| if (event.animationName !== 'modalShow' || !isModalOpen.value) { | |
| if (!isModalOpen.value || event.target !== event.currentTarget) { |
There was a problem hiding this comment.
This is true, Vue's scoped style adds a hash to both the element and the classes (including keyframes) to scope it. Im not sure if the suggested change makes sense tho.
@AdeshDeshmukh did you try the prod build on this? you can do pnpm build and then pnpm preview to run and test the production build.
What i would try would probably be something like:
if (!isModaOpen.value || !event.animationName.includes('modalShow')) {
I think that could work on both dev and prod regardless of the scoped style.
Another solution is to just make the style a global style (ie. remove the scoped attribute from the <style>) but i dont remember if this class would collapse with some other class (i doubt it tho).
javisperez
left a comment
There was a problem hiding this comment.
Check copilot's review, it makes sense.
|
I also noticed that there are unsigned commits, so that too needs to be fixed. |
Summary
This change fixes the Settings modal open lifecycle by replacing a timer-based body scroll lock with an animation-driven approach.
Problem
The modal previously used a hard-coded
setTimeout(150)inonMountedto addoverflow-hiddentodocument.body. This is brittle and can drift from actual animation timing.Root cause
UI state synchronization depended on elapsed time instead of the real completion event of the
modalShowanimation.Solution
onModalAnimationEnd(event: AnimationEvent)@animationend="onModalAnimationEnd"onMountedmodalShowwhile modal is openValidation
npx eslint src/components/SettingsModal.vuepassesRisk
Low. Change is localized to one component (
SettingsModal.vue) and only affects timing mechanism for applying body scroll lock.