mirror of
https://github.com/discourse/discourse.git
synced 2025-02-21 22:48:55 +08:00
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:
parent
875a413164
commit
f752851030
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user