software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
8.59k stars 1.26k forks source link

[Web LA] Add `JumpingTransition` #6148

Closed m-bert closed 1 week ago

m-bert commented 1 week ago

Summary

This PR adds JumpingTransition to transitions available on web 😄

Test plan

Tested on the following code (it is taken from docs so it throws some TypeScript errors, but it works fine) ```js import React, { useState, useRef, useEffect } from 'react'; import { View, Text, SafeAreaView, StyleSheet, TouchableOpacity, } from 'react-native'; import Animated, { LinearTransition, SequencedTransition, FadingTransition, FadeOut, useDerivedValue, withTiming, useSharedValue, useAnimatedStyle, withDelay, JumpingTransition, } from 'react-native-reanimated'; const DROPDOWN_OFFSET = 48; const INITIAL_LIST = [ { id: 1, emoji: '🍌', color: '#b58df1' }, { id: 2, emoji: '🍎', color: '#ffe780' }, { id: 3, emoji: '🥛', color: '#fa7f7c' }, { id: 4, emoji: '🍙', color: '#82cab2' }, { id: 5, emoji: '🍇', color: '#fa7f7c' }, { id: 6, emoji: '🍕', color: '#b58df1' }, { id: 7, emoji: '🍔', color: '#ffe780' }, { id: 8, emoji: '🍟', color: '#b58df1' }, { id: 9, emoji: '🍩', color: '#82cab2' }, { id: 10, emoji: '🍌', color: '#b58df1' }, { id: 11, emoji: '🥛', color: '#fa7f7c' }, { id: 12, emoji: '🍎', color: '#ffe780' }, { id: 13, emoji: '🥛', color: '#fa7f7c' }, { id: 14, emoji: '🍙', color: '#82cab2' }, { id: 15, emoji: '🍇', color: '#fa7f7c' }, { id: 16, emoji: '🍕', color: '#b58df1' }, { id: 17, emoji: '🍔', color: '#ffe780' }, { id: 18, emoji: '🍟', color: '#b58df1' }, { id: 19, emoji: '🍩', color: '#82cab2' }, ]; const LAYOUT_TRANSITIONS = [ { label: 'Linear Transition', value: LinearTransition }, { label: 'Sequenced Transition', value: SequencedTransition }, { label: 'Fading Transition', value: FadingTransition }, { label: 'Jumping Transition', value: JumpingTransition }, ]; const DropdownItems = ({ isExpanded, selected, setSelected }) => { const selectItem = (item) => { setSelected(item); isExpanded.value = !isExpanded.value; }; return ( {LAYOUT_TRANSITIONS.filter((item) => item.label != selected.label).map( (transition, index) => ( selectItem(transition)}> {transition.label} ) )} ); }; const DropdownItem = ({ isExpanded, children }) => { const height = useSharedValue(0); const derivedHeight = useDerivedValue(() => withTiming(height.value * Number(isExpanded.value), { duration: 500, }) ); const bodyStyle = useAnimatedStyle(() => ({ height: derivedHeight.value, })); return ( { height.value = e.nativeEvent.layout.height; }} style={styles.wrapper}> {children} ); }; const DropdownParent = ({ selected, setSelected, isExpanded }) => { return ( ); }; const Dropdown = ({ selected, onSelect }) => { const isExpanded = useSharedValue(false); const onPress = () => { console.log(isExpanded.value); isExpanded.value = !isExpanded.value; console.log(isExpanded.value); }; const labelRef = useRef(); const dropdownBackgroundAnimatedStyles = useAnimatedStyle(() => { const colorValue = isExpanded.value ? '#c1c6e5' : '#eef0ff'; return { backgroundColor: withDelay(50, withTiming(colorValue)), }; }); const dropdownListAnimatedStyles = useAnimatedStyle(() => { const paddingValue = isExpanded.value ? 8 : 0; return { paddingBottom: withDelay(50, withTiming(paddingValue)), }; }); return ( {selected.label} ); }; const dropdownStyles = StyleSheet.create({ container: { display: 'flex', flexDirection: 'row', justifyContent: 'center', zIndex: 2, position: 'relative', marginBottom: 8, }, items: { flexDirection: 'column', position: 'absolute', minWidth: 300, zIndex: -1, }, item: { margin: 8, }, label: { fontFamily: 'Aeonik', color: '#001a72', fontSize: 16, textAlign: 'center', }, selectedLabel: { fontWeight: '500', padding: 16, minWidth: 300, }, }); export default function App() { const [items, setItems] = useState(INITIAL_LIST); const [selected, setSelected] = useState(LAYOUT_TRANSITIONS[0]); const removeItem = (idToRemove) => { const updatedItems = items.filter((item) => item.id !== idToRemove); setItems(updatedItems); }; const onSelect = (item) => { setSelected(item); setItems(INITIAL_LIST); }; return ( ); } function Items({ selected, items, onRemove }) { return ( {items.map((item) => ( onRemove(item.id)} /> ))} ); } function Tile({ emoji, onRemove }) { return ( {emoji} ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 32, width: 'auto', display: 'flex', minHeight: 300, }, gridContainer: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'flex-start', justifyContent: 'center', paddingHorizontal: 32, }, tileContainer: { width: '20%', margin: '1%', borderRadius: 16, minHeight: 80, justifyContent: 'center', alignItems: 'center', }, tile: { flex: 1, height: '100%', width: ' 100%', justifyContent: 'center', alignItems: 'center', }, tileLabel: { color: '#f8f9ff', fontSize: 24, }, wrapper: { width: '100%', position: 'absolute', display: 'flex', alignItems: 'center', }, animatedView: { width: '100%', overflow: 'hidden', }, }); ```