Skip to content

Commit

Permalink
[Improvement]
Browse files Browse the repository at this point in the history
    1. position translation has implemented
    2. naming has been changed
              onPressListItem >   onPressFabItem
              ItemList >  fabItems
    3. Bug that state was not synced with UI has fixed
  • Loading branch information
Juyeong-Byeon committed Sep 16, 2021
1 parent f2a89e2 commit 4535cf5
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 74 deletions.
133 changes: 66 additions & 67 deletions main/FAB/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,23 @@ import {Animated, Easing, StyleProp, View, ViewStyle} from 'react-native';
import {ButtonSize, IconButton} from '../IconButton';
import {DoobooTheme, withTheme} from '../theme';
import {Icon, IconName} from '../Icon';
import React, {ReactElement, useEffect, useRef, useState} from 'react';
import React, {ReactElement, useLayoutEffect, useMemo, useRef} from 'react';

import styled from '@emotion/native';

export const StyledIcon = styled(Icon)`
color: ${({theme}) => theme.textContrast};
`;

const FABItemWrapper = styled.View`
margin: 10px;
`;

export interface FABItem {
icon: IconName;
id: string;
}

export interface FABProps<Item extends FABItem> {
isActive: boolean;
ItemList: Item[];
fabItems: Item[];
onPressFAB: () => void;
onPressListItem: (item?: Item) => void;
onPressFabItem: (item?: Item) => void;
renderFAB?: () => ReactElement;
renderFabItem?: (item: Item, idx: number) => ReactElement;
size: ButtonSize;
Expand All @@ -32,36 +27,52 @@ export interface FABProps<Item extends FABItem> {

function FloatingActionButtons<Item extends FABItem = FABItem>({
isActive,
theme,
ItemList,
fabItems,
onPressFAB,
onPressListItem,
onPressFabItem,
renderFAB,
renderFabItem,
size = 'large',
style,
}: FABProps<Item> & {
theme: DoobooTheme;
}): ReactElement {
const fadeAnim = useRef(new Animated.Value(0));
const spinValue = useRef(new Animated.Value(0));
const positionValue = useRef(new Animated.Value(0));

useEffect(() => {
return Animated.timing(fadeAnim.current, {
useLayoutEffect(() => {
Animated.timing(spinValue.current, {
toValue: isActive ? 1 : 0,
duration: 300,
easing: Easing.linear,
useNativeDriver: true,
easing: Easing.quad,
duration: 200,
}).start();
}, [fadeAnim, isActive]);
}, [isActive]);

useEffect(() => {
Animated.timing(fadeAnim.current, {
toValue: 1,
duration: 200,
useLayoutEffect(() => {
Animated.timing(positionValue.current, {
toValue: isActive ? 1 : 0,
duration: 300,
easing: Easing.linear,
useNativeDriver: true,
}).start();
}, [fadeAnim]);
}, [isActive]);

const spin = spinValue.current.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '45deg'],
});

const offsetAnimationList = useMemo(
() =>
fabItems?.map((_, idx) => {
return positionValue.current.interpolate({
inputRange: [0, 1],
outputRange: ['0%', `-${(idx + 1) * 80}%`],
});
}),
[fabItems],
);

return (
<View
Expand All @@ -75,52 +86,40 @@ function FloatingActionButtons<Item extends FABItem = FABItem>({
},
style,
]}>
<Animated.View>
{isActive &&
ItemList.map((item, idx) => {
return (
<FABItemWrapper
key={item.id}
style={{
position: 'absolute',
transform: [{translateY: -80 * (idx + 1)}],
}}>
{renderFabItem ? (
renderFabItem(item, idx)
) : (
<IconButton
testID={item.id}
size={size}
icon={
<StyledIcon theme={theme} size={24} name={item.icon} />
}
onPress={() => onPressListItem(item)}
/>
)}
</FABItemWrapper>
);
})}
{fabItems.map((item, idx) => {
return (
<Animated.View
key={item.id}
style={{
margin: 10,
position: 'absolute',
transform: [{translateY: offsetAnimationList[idx]}],
}}>
{renderFabItem ? (
renderFabItem(item, idx)
) : (
<IconButton
testID={item.id}
size={size}
icon={<StyledIcon size={24} name={item.icon} />}
onPress={() => onPressFabItem(item)}
/>
)}
</Animated.View>
);
})}
<Animated.View style={{transform: [{rotate: spin}], margin: 10}}>
{renderFAB ? (
renderFAB()
) : (
<IconButton
testID={'main_fab'}
size={size}
icon={<StyledIcon size={24} name="add-light" />}
onPress={onPressFAB}
/>
)}
</Animated.View>
<FABItemWrapper>
<Animated.View>
{renderFAB ? (
renderFAB()
) : (
<IconButton
testID={'main_fab'}
size={size}
icon={
isActive ? (
<StyledIcon size={24} name="cross-light" />
) : (
<StyledIcon size={24} name="add-light" />
)
}
onPress={onPressFAB}
/>
)}
</Animated.View>
</FABItemWrapper>
</View>
);
}
Expand Down
8 changes: 4 additions & 4 deletions main/__tests__/FAB.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ describe('[FAB]', () => {

const {getByTestId} = render(
Component({
ItemList: [item],
fabItems: [item],
isActive: true,
size: 'large',
onPressListItem: (item) => {
onPressFabItem: (item) => {
count += 1;
resItem = item;
},
Expand All @@ -37,10 +37,10 @@ describe('[FAB]', () => {
it('should render customFAB', async () => {
const testingLib = render(
Component({
ItemList: [{icon: 'bell-solid', id: 'item1'}],
fabItems: [{icon: 'bell-solid', id: 'item1'}],
isActive: true,
size: 'large',
onPressListItem: (item1) => {},
onPressFabItem: (item1) => {},
onPressFAB: () => {},
renderFAB: () => <View />,
renderFabItem: (item, idx) => <View />,
Expand Down
6 changes: 3 additions & 3 deletions stories/dooboo-ui/FloatingActionButton/FABStory.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, {FC, useState} from 'react';
import {SafeAreaView, View} from 'react-native';
import {useTheme, withTheme} from '../../../main/theme/ThemeProvider';

import {FAB} from '../../../main';
import styled from '@emotion/native';
import {useFonts} from 'expo-font';
import {withTheme} from '../../../main/theme/ThemeProvider';

const StoryContainer = styled.View`
flex: 1;
Expand All @@ -28,11 +28,11 @@ const FABContainer: FC = () => {
size="medium"
isActive={active}
onPressFAB={() => setActive((prev) => !prev)}
ItemList={[
fabItems={[
{id: 'search', icon: 'home-light'},
{id: 'like', icon: 'like-light'},
]}
onPressListItem={(item) => {
onPressFabItem={(item) => {
console.log(item);
}}
/>
Expand Down

0 comments on commit 4535cf5

Please sign in to comment.