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 {
|
&.animated {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: none;
|
transform: translateY(-50%);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
will-change: width, height, top, left;
|
will-change: width, height, top, left;
|
||||||
|
|
||||||
|
@ -54,6 +54,12 @@
|
||||||
& * {
|
& * {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
& {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bottom {
|
&.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) => {
|
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
||||||
let element: HTMLDialogElement;
|
let element: HTMLDialogElement;
|
||||||
|
@ -62,13 +62,17 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
hero()!.style.visibility = 'unset'
|
const srcElement = hero();
|
||||||
|
if (srcElement) {
|
||||||
|
srcElement.style.visibility = "unset";
|
||||||
|
}
|
||||||
|
|
||||||
element.close();
|
element.close();
|
||||||
setHero();
|
setHero();
|
||||||
};
|
};
|
||||||
|
|
||||||
const animatedClose = () => {
|
const animatedClose = () => {
|
||||||
const srcElement = hero()
|
const srcElement = hero();
|
||||||
const endRect = srcElement?.getBoundingClientRect();
|
const endRect = srcElement?.getBoundingClientRect();
|
||||||
if (endRect) {
|
if (endRect) {
|
||||||
const startRect = element.getBoundingClientRect();
|
const startRect = element.getBoundingClientRect();
|
||||||
|
@ -76,19 +80,88 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
||||||
animation.addEventListener("finish", onClose);
|
animation.addEventListener("finish", onClose);
|
||||||
animation.addEventListener("cancel", onClose);
|
animation.addEventListener("cancel", onClose);
|
||||||
} else {
|
} else {
|
||||||
element.close();
|
if (window.innerWidth > 560 && !props.bottomUp) {
|
||||||
setHero();
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const animation = props.bottomUp
|
||||||
|
? animateSlideInFromBottom(element, true)
|
||||||
|
: animateSlideInFromRight(element, true);
|
||||||
|
animation.addEventListener("finish", onClose);
|
||||||
|
animation.addEventListener("cancel", onClose);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const animatedOpen = () => {
|
const animatedOpen = () => {
|
||||||
element.showModal();
|
element.showModal();
|
||||||
const srcElement = hero()
|
const srcElement = hero();
|
||||||
const startRect = srcElement?.getBoundingClientRect();
|
const startRect = srcElement?.getBoundingClientRect();
|
||||||
if (!startRect) return;
|
if (startRect) {
|
||||||
srcElement!.style.visibility = 'hidden'
|
srcElement!.style.visibility = "hidden";
|
||||||
const endRect = element.getBoundingClientRect();
|
const endRect = element.getBoundingClientRect();
|
||||||
animateHero(startRect, endRect, element);
|
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 = (
|
const animateHero = (
|
||||||
|
|
Loading…
Reference in a new issue