BottomSheet: more animation
This commit is contained in:
parent
7d3c97c56b
commit
4fb5582b3d
2 changed files with 90 additions and 11 deletions
|
@ -43,7 +43,7 @@
|
|||
|
||||
&.animated {
|
||||
position: absolute;
|
||||
transform: none;
|
||||
transform: translateY(-50%);
|
||||
overflow: hidden;
|
||||
will-change: width, height, top, left;
|
||||
|
||||
|
@ -54,6 +54,12 @@
|
|||
& * {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
& {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
|
|
|
@ -36,7 +36,7 @@ function composeAnimationFrame(
|
|||
};
|
||||
}
|
||||
|
||||
const MOVE_SPEED = 1400; // 1400px/s, bottom sheet is big and a bit heavier than small papers
|
||||
const MOVE_SPEED = 1200;
|
||||
|
||||
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
||||
let element: HTMLDialogElement;
|
||||
|
@ -62,13 +62,17 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
|||
});
|
||||
|
||||
const onClose = () => {
|
||||
hero()!.style.visibility = 'unset'
|
||||
const srcElement = hero();
|
||||
if (srcElement) {
|
||||
srcElement.style.visibility = "unset";
|
||||
}
|
||||
|
||||
element.close();
|
||||
setHero();
|
||||
};
|
||||
|
||||
const animatedClose = () => {
|
||||
const srcElement = hero()
|
||||
const srcElement = hero();
|
||||
const endRect = srcElement?.getBoundingClientRect();
|
||||
if (endRect) {
|
||||
const startRect = element.getBoundingClientRect();
|
||||
|
@ -76,19 +80,88 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
|||
animation.addEventListener("finish", onClose);
|
||||
animation.addEventListener("cancel", onClose);
|
||||
} else {
|
||||
element.close();
|
||||
setHero();
|
||||
if (window.innerWidth > 560 && !props.bottomUp) {
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
const animation = props.bottomUp
|
||||
? animateSlideInFromBottom(element, true)
|
||||
: animateSlideInFromRight(element, true);
|
||||
animation.addEventListener("finish", onClose);
|
||||
animation.addEventListener("cancel", onClose);
|
||||
}
|
||||
};
|
||||
|
||||
const animatedOpen = () => {
|
||||
element.showModal();
|
||||
const srcElement = hero()
|
||||
const srcElement = hero();
|
||||
const startRect = srcElement?.getBoundingClientRect();
|
||||
if (!startRect) return;
|
||||
srcElement!.style.visibility = 'hidden'
|
||||
const endRect = element.getBoundingClientRect();
|
||||
animateHero(startRect, endRect, element);
|
||||
if (startRect) {
|
||||
srcElement!.style.visibility = "hidden";
|
||||
const endRect = element.getBoundingClientRect();
|
||||
animateHero(startRect, endRect, element);
|
||||
} else if (props.bottomUp) {
|
||||
animateSlideInFromBottom(element);
|
||||
} else if (window.innerWidth <= 560) {
|
||||
animateSlideInFromRight(element);
|
||||
}
|
||||
};
|
||||
|
||||
const animateSlideInFromRight = (element: HTMLElement, reserve?: boolean) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const easing = "cubic-bezier(0.4, 0, 0.2, 1)";
|
||||
element.classList.add(styles.animated);
|
||||
const distance = Math.abs(rect.left - window.innerWidth);
|
||||
const duration = (distance / MOVE_SPEED) * 1000;
|
||||
|
||||
animation = element.animate(
|
||||
{
|
||||
top: [rect.top, rect.top],
|
||||
left: reserve
|
||||
? [`${rect.left}px`, `${window.innerWidth}px`]
|
||||
: [`${window.innerWidth}px`, `${rect.left}px`],
|
||||
width: [rect.width, rect.width],
|
||||
height: [rect.height, rect.height],
|
||||
},
|
||||
{ easing, duration },
|
||||
);
|
||||
const onAnimationEnd = () => {
|
||||
element.classList.remove(styles.animated);
|
||||
animation = undefined;
|
||||
};
|
||||
animation.addEventListener("cancel", onAnimationEnd);
|
||||
animation.addEventListener("finish", onAnimationEnd);
|
||||
return animation;
|
||||
};
|
||||
|
||||
const animateSlideInFromBottom = (
|
||||
element: HTMLElement,
|
||||
reserve?: boolean,
|
||||
) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const easing = "cubic-bezier(0.4, 0, 0.2, 1)";
|
||||
element.classList.add(styles.animated);
|
||||
const distance = Math.abs(rect.top - window.innerHeight);
|
||||
const duration = (distance / MOVE_SPEED) * 1000;
|
||||
|
||||
animation = element.animate(
|
||||
{
|
||||
left: [rect.left, rect.left],
|
||||
top: reserve
|
||||
? [`${rect.top}px`, `${window.innerHeight}px`]
|
||||
: [`${window.innerHeight}px`, `${rect.top}px`],
|
||||
width: [rect.width, rect.width],
|
||||
height: [rect.height, rect.height],
|
||||
},
|
||||
{ easing, duration },
|
||||
);
|
||||
const onAnimationEnd = () => {
|
||||
element.classList.remove(styles.animated);
|
||||
animation = undefined;
|
||||
};
|
||||
animation.addEventListener("cancel", onAnimationEnd);
|
||||
animation.addEventListener("finish", onAnimationEnd);
|
||||
return animation;
|
||||
};
|
||||
|
||||
const animateHero = (
|
||||
|
|
Loading…
Reference in a new issue