animation
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
Animated,
|
||||||
|
Easing,
|
||||||
FlatList,
|
FlatList,
|
||||||
Image,
|
Image,
|
||||||
Pressable,
|
Pressable,
|
||||||
@@ -43,6 +45,7 @@ const ProjectDropDown = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [triggerLayout, setTriggerLayout] = useState(null);
|
const [triggerLayout, setTriggerLayout] = useState(null);
|
||||||
|
const dropdownAnimation = useRef(new Animated.Value(0)).current;
|
||||||
|
|
||||||
const normalizedProjects = Array.isArray(projects) ? projects : [];
|
const normalizedProjects = Array.isArray(projects) ? projects : [];
|
||||||
const isDisabled = normalizedProjects.length === 0;
|
const isDisabled = normalizedProjects.length === 0;
|
||||||
@@ -102,6 +105,52 @@ const ProjectDropDown = ({
|
|||||||
[triggerLayout],
|
[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 (
|
return (
|
||||||
<View style={[styles.container, style]}>
|
<View style={[styles.container, style]}>
|
||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
@@ -112,44 +161,63 @@ const ProjectDropDown = ({
|
|||||||
style={styles.triggerWrapper}
|
style={styles.triggerWrapper}
|
||||||
onLayout={(event) => setTriggerLayout(event.nativeEvent.layout)}
|
onLayout={(event) => setTriggerLayout(event.nativeEvent.layout)}
|
||||||
>
|
>
|
||||||
<BlurView
|
<Animated.View
|
||||||
intensity={BUTTON_BLUR_INTENSITY}
|
pointerEvents={isOpen ? "none" : "auto"}
|
||||||
tint="dark"
|
|
||||||
style={[
|
style={[
|
||||||
styles.dropdownBlur,
|
styles.dropdownTriggerContainer,
|
||||||
isDisabled && styles.dropdownBlurDisabled,
|
{
|
||||||
isOpen && styles.dropdownBlurHidden,
|
opacity: triggerOpacity,
|
||||||
|
transform: [{ translateY: triggerTranslateY }],
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<ProjectRow
|
<BlurView
|
||||||
isTitle={true}
|
intensity={BUTTON_BLUR_INTENSITY}
|
||||||
isOpen={isOpen}
|
tint="dark"
|
||||||
project={currentProject}
|
style={[
|
||||||
formatDate={formatDate}
|
styles.dropdownBlur,
|
||||||
onSelect={toggleDropdown}
|
isDisabled && styles.dropdownBlurDisabled,
|
||||||
/>
|
]}
|
||||||
</BlurView>
|
>
|
||||||
|
<ProjectRow
|
||||||
|
isTitle={true}
|
||||||
|
isOpen={isOpen}
|
||||||
|
project={currentProject}
|
||||||
|
formatDate={formatDate}
|
||||||
|
onSelect={toggleDropdown}
|
||||||
|
/>
|
||||||
|
</BlurView>
|
||||||
|
</Animated.View>
|
||||||
|
|
||||||
<BlurView
|
<Animated.View
|
||||||
intensity={BUTTON_BLUR_INTENSITY}
|
|
||||||
tint="dark"
|
|
||||||
pointerEvents={isOpen ? "auto" : "none"}
|
pointerEvents={isOpen ? "auto" : "none"}
|
||||||
style={[
|
style={[
|
||||||
styles.dropdownOverlay,
|
styles.dropdownOverlayContainer,
|
||||||
{ width: dropdownWidth || "100%" },
|
{ width: dropdownWidth || "100%" },
|
||||||
!isOpen && styles.dropdownOverlayHidden,
|
{
|
||||||
|
opacity: dropdownAnimation,
|
||||||
|
transform: [
|
||||||
|
{ translateY: overlayTranslateY },
|
||||||
|
{ scale: overlayScale },
|
||||||
|
],
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<ProjectRow
|
<BlurView
|
||||||
isTitle={true}
|
intensity={BUTTON_BLUR_INTENSITY}
|
||||||
isOpen={isOpen}
|
tint="dark"
|
||||||
project={currentProject}
|
style={styles.dropdownOverlay}
|
||||||
formatDate={formatDate}
|
>
|
||||||
onSelect={toggleDropdown}
|
<ProjectRow
|
||||||
/>
|
isTitle={true}
|
||||||
|
isOpen={isOpen}
|
||||||
|
project={currentProject}
|
||||||
|
formatDate={formatDate}
|
||||||
|
onSelect={toggleDropdown}
|
||||||
|
/>
|
||||||
|
|
||||||
<View style={styles.dropdownOverlayContent}>
|
<View style={styles.dropdownOverlayContent}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={dropdownProjects}
|
data={dropdownProjects}
|
||||||
keyExtractor={(project, index) =>
|
keyExtractor={(project, index) =>
|
||||||
project?.id || project?.title || `project-${index}`
|
project?.id || project?.title || `project-${index}`
|
||||||
@@ -168,13 +236,14 @@ const ProjectDropDown = ({
|
|||||||
contentContainerStyle={styles.dropdownListContent}
|
contentContainerStyle={styles.dropdownListContent}
|
||||||
style={styles.dropdownList}
|
style={styles.dropdownList}
|
||||||
/>
|
/>
|
||||||
<GradientButton
|
<GradientButton
|
||||||
containerStyle={styles.createButtonContainer}
|
containerStyle={styles.createButtonContainer}
|
||||||
title="Commencer à créer"
|
title="Commencer à créer"
|
||||||
onPress={handleCreate}
|
onPress={handleCreate}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</BlurView>
|
</BlurView>
|
||||||
|
</Animated.View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -295,29 +364,30 @@ const styles = StyleSheet.create({
|
|||||||
dropdownBlurDisabled: {
|
dropdownBlurDisabled: {
|
||||||
opacity: 0.6,
|
opacity: 0.6,
|
||||||
},
|
},
|
||||||
dropdownBlurHidden: {
|
|
||||||
opacity: 0,
|
|
||||||
pointerEvents: "none",
|
|
||||||
},
|
|
||||||
triggerWrapper: {
|
triggerWrapper: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
zIndex: 3,
|
zIndex: 3,
|
||||||
},
|
},
|
||||||
dropdownOverlay: {
|
dropdownTriggerContainer: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
dropdownOverlayContainer: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
borderRadius: 16,
|
borderRadius: 16,
|
||||||
|
overflow: "hidden",
|
||||||
|
zIndex: 4,
|
||||||
|
elevation: 4,
|
||||||
|
maxHeight: 400,
|
||||||
|
},
|
||||||
|
dropdownOverlay: {
|
||||||
|
flex: 1,
|
||||||
|
width: "100%",
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
paddingVertical: 8,
|
paddingVertical: 8,
|
||||||
gap: 9,
|
gap: 9,
|
||||||
maxHeight: 400,
|
maxHeight: 400,
|
||||||
zIndex: 4,
|
|
||||||
elevation: 4,
|
|
||||||
overflow: "hidden",
|
|
||||||
},
|
|
||||||
dropdownOverlayHidden: {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
},
|
||||||
dropdownOverlayContent: {
|
dropdownOverlayContent: {
|
||||||
maxHeight: 260,
|
maxHeight: 260,
|
||||||
|
|||||||
Reference in New Issue
Block a user