animation

This commit is contained in:
Thomas Demirdjian
2025-10-03 17:25:44 +02:00
parent 45b7571c14
commit 3d14e47770
@@ -1,5 +1,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
Animated,
Easing,
FlatList,
Image,
Pressable,
@@ -43,6 +45,7 @@ const ProjectDropDown = ({
}) => {
const [isOpen, setIsOpen] = useState(false);
const [triggerLayout, setTriggerLayout] = useState(null);
const dropdownAnimation = useRef(new Animated.Value(0)).current;
const normalizedProjects = Array.isArray(projects) ? projects : [];
const isDisabled = normalizedProjects.length === 0;
@@ -102,6 +105,52 @@ const ProjectDropDown = ({
[triggerLayout],
);
useEffect(() => {
Animated.timing(dropdownAnimation, {
toValue: isOpen ? 1 : 0,
duration: 220,
easing: isOpen ? Easing.out(Easing.cubic) : Easing.in(Easing.cubic),
useNativeDriver: true,
}).start();
}, [dropdownAnimation, isOpen]);
const overlayTranslateY = useMemo(
() =>
dropdownAnimation.interpolate({
inputRange: [0, 1],
outputRange: [-12, 0],
}),
[dropdownAnimation],
);
const overlayScale = useMemo(
() =>
dropdownAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0.96, 1],
}),
[dropdownAnimation],
);
const triggerOpacity = useMemo(
() =>
dropdownAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
extrapolate: "clamp",
}),
[dropdownAnimation],
);
const triggerTranslateY = useMemo(
() =>
dropdownAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0, -6],
}),
[dropdownAnimation],
);
return (
<View style={[styles.container, style]}>
{isOpen ? (
@@ -111,6 +160,16 @@ const ProjectDropDown = ({
<View
style={styles.triggerWrapper}
onLayout={(event) => setTriggerLayout(event.nativeEvent.layout)}
>
<Animated.View
pointerEvents={isOpen ? "none" : "auto"}
style={[
styles.dropdownTriggerContainer,
{
opacity: triggerOpacity,
transform: [{ translateY: triggerTranslateY }],
},
]}
>
<BlurView
intensity={BUTTON_BLUR_INTENSITY}
@@ -118,7 +177,6 @@ const ProjectDropDown = ({
style={[
styles.dropdownBlur,
isDisabled && styles.dropdownBlurDisabled,
isOpen && styles.dropdownBlurHidden,
]}
>
<ProjectRow
@@ -129,16 +187,26 @@ const ProjectDropDown = ({
onSelect={toggleDropdown}
/>
</BlurView>
</Animated.View>
<Animated.View
pointerEvents={isOpen ? "auto" : "none"}
style={[
styles.dropdownOverlayContainer,
{ width: dropdownWidth || "100%" },
{
opacity: dropdownAnimation,
transform: [
{ translateY: overlayTranslateY },
{ scale: overlayScale },
],
},
]}
>
<BlurView
intensity={BUTTON_BLUR_INTENSITY}
tint="dark"
pointerEvents={isOpen ? "auto" : "none"}
style={[
styles.dropdownOverlay,
{ width: dropdownWidth || "100%" },
!isOpen && styles.dropdownOverlayHidden,
]}
style={styles.dropdownOverlay}
>
<ProjectRow
isTitle={true}
@@ -175,6 +243,7 @@ const ProjectDropDown = ({
/>
</View>
</BlurView>
</Animated.View>
</View>
</View>
);
@@ -295,29 +364,30 @@ const styles = StyleSheet.create({
dropdownBlurDisabled: {
opacity: 0.6,
},
dropdownBlurHidden: {
opacity: 0,
pointerEvents: "none",
},
triggerWrapper: {
position: "relative",
zIndex: 3,
},
dropdownOverlay: {
dropdownTriggerContainer: {
width: "100%",
},
dropdownOverlayContainer: {
position: "absolute",
top: 0,
left: 0,
borderRadius: 16,
overflow: "hidden",
zIndex: 4,
elevation: 4,
maxHeight: 400,
},
dropdownOverlay: {
flex: 1,
width: "100%",
paddingHorizontal: 8,
paddingVertical: 8,
gap: 9,
maxHeight: 400,
zIndex: 4,
elevation: 4,
overflow: "hidden",
},
dropdownOverlayHidden: {
opacity: 0,
},
dropdownOverlayContent: {
maxHeight: 260,