FIX: mobile modal tweaks (#27073)

- removes `will-change: auto;` which is a performance hack which should be avoided and is probably causing more harm than good here
- lowers swipe velocity to 0.4 to ensure the modal can be dismissed with the thumb
- uses JS CSS animate API to animate the backdrop opacity
- uses the height of the modal container to have more precise values when computing backdrop opacity
- animate the modal container instead of the wrapper
- removes a useless template-lint-disable directive
- simplify the closing animation
- various small code tweaks to limit indirection
This commit is contained in:
Joffrey JAFFEUX 2024-05-19 15:43:03 +02:00 committed by GitHub
parent 875a413164
commit f752851030
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 37 deletions

View File

@ -29,7 +29,7 @@ export const CLOSE_INITIATED_BY_SWIPE_DOWN = "initiatedBySwipeDown";
const FLASH_TYPES = ["success", "error", "warning", "info"]; const FLASH_TYPES = ["success", "error", "warning", "info"];
const SWIPE_VELOCITY_THRESHOLD = 0.7; const SWIPE_VELOCITY_THRESHOLD = 0.4;
export default class DModal extends Component { export default class DModal extends Component {
@service modal; @service modal;
@ -39,15 +39,19 @@ export default class DModal extends Component {
@tracked wrapperElement; @tracked wrapperElement;
@tracked animating = false; @tracked animating = false;
registerModalContainer = modifierFn((element) => {
this.modalContainer = element;
});
setupModalBody = modifierFn((element) => { setupModalBody = modifierFn((element) => {
if (this.site.mobileView) { if (!this.site.mobileView) {
disableBodyScroll(element); return;
} }
disableBodyScroll(element);
return () => { return () => {
if (this.site.mobileView) {
enableBodyScroll(element); enableBodyScroll(element);
}
}; };
}); });
@ -139,19 +143,15 @@ export default class DModal extends Component {
return; return;
} }
if (swipeEvent.goingUp()) { if (
swipeEvent.goingUp() ||
swipeEvent.velocityY < SWIPE_VELOCITY_THRESHOLD
) {
return await this.#animateWrapperPosition(0); return await this.#animateWrapperPosition(0);
} }
if (swipeEvent.velocityY >= SWIPE_VELOCITY_THRESHOLD) { this.modalContainer.style.transform = `translateY(${swipeEvent.deltaY}px)`;
this.wrapperElement.querySelector(
".d-modal__container"
).style.transform = `translateY(${swipeEvent.deltaY}px)`;
this.closeModal(CLOSE_INITIATED_BY_SWIPE_DOWN); this.closeModal(CLOSE_INITIATED_BY_SWIPE_DOWN);
} else {
return await this.#animateWrapperPosition(0);
}
} }
@action @action
@ -178,15 +178,8 @@ export default class DModal extends Component {
this.#animateBackdropOpacity(window.innerHeight); this.#animateBackdropOpacity(window.innerHeight);
await this.wrapperElement.animate( await this.#animateWrapperPosition(this.modalContainer.clientHeight);
[
// hidding first ms to avoid flicker
{ visibility: "hidden", offset: 0 },
{ visibility: "visible", offset: 0.01 },
{ transform: "translateY(100%)", offset: 1 },
],
{ duration: getMaxAnimationTimeMs(), fill: "forwards" }
).finished;
this.animating = false; this.animating = false;
} }
@ -252,21 +245,16 @@ export default class DModal extends Component {
return; return;
} }
// 85vh is the max height of the modal const opacity = 1 - position / this.modalContainer.clientHeight;
const opacity = 1 - position / (window.innerHeight * 0.85); backdrop.animate([{ opacity: Math.max(0, Math.min(opacity, 0.6)) }], {
requestAnimationFrame(() => { fill: "forwards",
backdrop.style.setProperty(
"opacity",
Math.max(0, Math.min(opacity, 0.6)),
"important"
);
}); });
} }
async #animateWrapperPosition(position) { async #animateWrapperPosition(position) {
this.#animateBackdropOpacity(position); this.#animateBackdropOpacity(position);
await this.wrapperElement.animate( await this.modalContainer.animate(
[{ transform: `translateY(${position}px)` }], [{ transform: `translateY(${position}px)` }],
{ {
fill: "forwards", fill: "forwards",
@ -276,7 +264,6 @@ export default class DModal extends Component {
} }
<template> <template>
{{! template-lint-disable no-pointer-down-event-binding }}
{{! template-lint-disable no-invalid-interactive }} {{! template-lint-disable no-invalid-interactive }}
<ConditionalInElement <ConditionalInElement
@ -300,7 +287,7 @@ export default class DModal extends Component {
{{willDestroy this.cleanupModal}} {{willDestroy this.cleanupModal}}
{{trapTab preventScroll=false}} {{trapTab preventScroll=false}}
> >
<div class="d-modal__container"> <div class="d-modal__container" {{this.registerModalContainer}}>
{{yield to="aboveHeader"}} {{yield to="aboveHeader"}}
{{#if {{#if

View File

@ -34,7 +34,6 @@ html:not(.keyboard-visible.mobile-view) {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
max-height: calc(var(--composer-vh, var(--1dvh)) * 85); max-height: calc(var(--composer-vh, var(--1dvh)) * 85);
will-change: auto;
} }
&__header { &__header {