mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-09-15 23:32:25 +03:00
Completely revise the animations for the context menu to be compatible with Firefox for Android (worked everywhere else amusingly)
This commit is contained in:
parent
4963142ed4
commit
a4c5d1a6f9
2 changed files with 67 additions and 39 deletions
|
@ -1,10 +1,21 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useSpring, animated } from '@react-spring/web';
|
|
||||||
import { useDrag } from 'react-use-gesture';
|
import { useDrag } from 'react-use-gesture';
|
||||||
import './MobileContextMenu.scss';
|
import './MobileContextMenu.scss';
|
||||||
|
|
||||||
export function MobileContextMenu({ isOpen, onClose, children }) {
|
export function MobileContextMenu({ isOpen, onClose, children }) {
|
||||||
const { innerHeight } = window;
|
const getInnerHeight = () => (typeof window !== 'undefined' ? window.innerHeight : 0);
|
||||||
|
const [y, setY] = useState(getInnerHeight());
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setY(isOpen ? 0 : getInnerHeight());
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
document.body.style.overscrollBehavior = 'contain';
|
document.body.style.overscrollBehavior = 'contain';
|
||||||
|
@ -14,51 +25,53 @@ export function MobileContextMenu({ isOpen, onClose, children }) {
|
||||||
};
|
};
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
const [{ y }, api] = useSpring(() => ({
|
|
||||||
y: innerHeight,
|
|
||||||
config: { tension: 250, friction: 25 },
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
api.start({ y: isOpen ? 0 : innerHeight });
|
|
||||||
}, [api, innerHeight, isOpen]);
|
|
||||||
|
|
||||||
const bind = useDrag(
|
const bind = useDrag(
|
||||||
({ last, movement: [, my], event }) => {
|
({ last, movement: [, my], down }) => {
|
||||||
|
if (down && !isDragging) {
|
||||||
|
setIsDragging(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newY = Math.max(my, 0);
|
||||||
|
setY(newY);
|
||||||
|
|
||||||
if (last) {
|
if (last) {
|
||||||
if (my > innerHeight / 4) {
|
setIsDragging(false);
|
||||||
event.preventDefault();
|
if (my > getInnerHeight() / 4) {
|
||||||
event.stopPropagation();
|
|
||||||
onClose();
|
onClose();
|
||||||
} else {
|
} else {
|
||||||
api.start({ y: 0 });
|
setY(0);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
api.start({ y: Math.max(my, 0), immediate: true });
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: () => [0, y.get()],
|
from: () => [0, y],
|
||||||
filterTaps: true,
|
filterTaps: true,
|
||||||
bounds: { top: 0 },
|
bounds: { top: 0 },
|
||||||
rubberband: true,
|
rubberband: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (!isOpen) return null;
|
|
||||||
|
if (!isOpen && y >= getInnerHeight()) return null;
|
||||||
|
const containerClasses = [
|
||||||
|
'bottom-sheet-container',
|
||||||
|
!isDragging ? 'is-transitioning' : '',
|
||||||
|
].join(' ');
|
||||||
|
|
||||||
|
const backdropOpacity = y > 0 ? 1 - y / getInnerHeight() : 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<animated.div
|
<div
|
||||||
className="bottom-sheet-backdrop"
|
className="bottom-sheet-backdrop"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
style={{ opacity: y.to([0, innerHeight], [1, 0], 'clamp') }}
|
style={{ opacity: Math.max(0, backdropOpacity) }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<animated.div
|
<div
|
||||||
className="bottom-sheet-container"
|
className={containerClasses}
|
||||||
{...bind()}
|
{...bind()}
|
||||||
style={{
|
style={{
|
||||||
y,
|
transform: `translate3d(0, ${y}px, 0)`,
|
||||||
touchAction: 'none',
|
touchAction: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -66,7 +79,7 @@ export function MobileContextMenu({ isOpen, onClose, children }) {
|
||||||
<div className="bottom-sheet-content" style={{ overflow: 'visible' }}>
|
<div className="bottom-sheet-content" style={{ overflow: 'visible' }}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</animated.div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,49 @@
|
||||||
.bottom-sheet-backdrop {
|
.bottom-sheet-backdrop {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
z-index: 1000;
|
// The backdrop fade will also be smoother with a transition
|
||||||
touch-action: none;
|
transition: opacity 300ms ease-out;
|
||||||
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-sheet-container {
|
.bottom-sheet-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1001;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
// Set transform from the component's style prop
|
||||||
|
// The 'will-change' property is a performance hint for the browser
|
||||||
|
will-change: transform;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
// Your existing styles for the sheet itself
|
||||||
|
border-top-left-radius: 16px;
|
||||||
|
border-top-right-radius: 16px;
|
||||||
|
box-shadow: 0 -2px A10px rgba(0, 0, 0, 0.1);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-height: 90vh;
|
|
||||||
border-radius: 16px 16px 0 0;
|
// This is the magic: apply a transition only when this class is present
|
||||||
box-shadow: 0px -4px B16px rgba(0, 0, 0, 0.15);
|
&.is-transitioning {
|
||||||
|
transition: transform 300ms ease-out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Your other styles remain the same
|
||||||
.bottom-sheet-grabber {
|
.bottom-sheet-grabber {
|
||||||
flex-shrink: 0;
|
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 2.5px;
|
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
|
border-radius: 2.5px;
|
||||||
margin: 8px auto;
|
margin: 8px auto;
|
||||||
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-sheet-content {
|
.bottom-sheet-content {
|
||||||
|
padding: 16px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0 1rem 1rem 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue