({
color,
size,
source,
theme: themeOverrides,
testID = 'cross-fade-icon',
}: Props)
| 29 | }; |
| 30 | |
| 31 | const CrossFadeIcon = ({ |
| 32 | color, |
| 33 | size, |
| 34 | source, |
| 35 | theme: themeOverrides, |
| 36 | testID = 'cross-fade-icon', |
| 37 | }: Props) => { |
| 38 | const theme = useInternalTheme(themeOverrides); |
| 39 | const [currentIcon, setCurrentIcon] = React.useState<IconSource>( |
| 40 | () => source |
| 41 | ); |
| 42 | const [previousIcon, setPreviousIcon] = React.useState<IconSource | null>( |
| 43 | null |
| 44 | ); |
| 45 | const { current: fade } = React.useRef<Animated.Value>(new Animated.Value(1)); |
| 46 | |
| 47 | const { scale } = theme.animation; |
| 48 | |
| 49 | if (currentIcon !== source) { |
| 50 | setPreviousIcon(() => currentIcon); |
| 51 | setCurrentIcon(() => source); |
| 52 | } |
| 53 | |
| 54 | React.useEffect(() => { |
| 55 | if (isValidIcon(previousIcon) && !isEqualIcon(previousIcon, currentIcon)) { |
| 56 | fade.setValue(1); |
| 57 | |
| 58 | Animated.timing(fade, { |
| 59 | duration: scale * 200, |
| 60 | toValue: 0, |
| 61 | useNativeDriver: true, |
| 62 | }).start(); |
| 63 | } |
| 64 | }, [currentIcon, previousIcon, fade, scale]); |
| 65 | |
| 66 | const opacityPrev = fade; |
| 67 | const opacityNext = previousIcon |
| 68 | ? fade.interpolate({ |
| 69 | inputRange: [0, 1], |
| 70 | outputRange: [1, 0], |
| 71 | }) |
| 72 | : 1; |
| 73 | |
| 74 | const rotatePrev = fade.interpolate({ |
| 75 | inputRange: [0, 1], |
| 76 | outputRange: ['-90deg', '0deg'], |
| 77 | }); |
| 78 | |
| 79 | const rotateNext = previousIcon |
| 80 | ? fade.interpolate({ |
| 81 | inputRange: [0, 1], |
| 82 | outputRange: ['0deg', '-180deg'], |
| 83 | }) |
| 84 | : '0deg'; |
| 85 | |
| 86 | return ( |
| 87 | <View |
| 88 | style={[ |
nothing calls this directly
no test coverage detected
searching dependent graphs…