Skip to content

Commit

Permalink
feat: bootstrap the library
Browse files Browse the repository at this point in the history
  • Loading branch information
Trancever committed Dec 12, 2020
1 parent b8e0181 commit 15efdcc
Show file tree
Hide file tree
Showing 26 changed files with 24,630 additions and 25 deletions.
7 changes: 7 additions & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@
"test": "jest"
},
"dependencies": {
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/stack": "^5.12.8",
"expo": "^38.0.0",
"expo-font": "~8.2.1",
"expo-splash-screen": "^0.3.1",
"react": "16.11.0",
"react-dom": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "~1.6.0",
"react-native-reanimated": "~1.9.0",
"react-native-safe-area-context": "~3.0.7",
"react-native-screens": "~2.9.0",
"react-native-unimodules": "~0.10.1",
"react-native-web": "^0.12.3"
},
Expand Down
57 changes: 40 additions & 17 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
import * as React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import ReanimatedAccordionHelpers from 'reanimated-accordion-helpers';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import * as Font from 'expo-font';

import { Home } from './Home';
import { Faq } from './examples/faq/Faq';
import {
Montserrat,
MontserratBold,
MontserratSemiBold,
OpenSans,
OpenSansBold,
OpenSansSemiBold,
} from './fonts';

const Stack = createStackNavigator();

export default function App() {
const [result, setResult] = React.useState<number | undefined>();
const [fontsLoaded] = Font.useFonts({
[OpenSans]: require('./assets/fonts/OpenSans-Regular.ttf'),
[OpenSansBold]: require('./assets/fonts/OpenSans-Bold.ttf'),
[OpenSansSemiBold]: require('./assets/fonts/OpenSans-SemiBold.ttf'),
[Montserrat]: require('./assets/fonts/Montserrat-Regular.ttf'),
[MontserratSemiBold]: require('./assets/fonts/Montserrat-SemiBold.ttf'),
[MontserratBold]: require('./assets/fonts/Montserrat-Bold.ttf'),
});

React.useEffect(() => {
ReanimatedAccordionHelpers.multiply(3, 7).then(setResult);
}, []);
if (!fontsLoaded) return null;

return (
<View style={styles.container}>
<Text>Result: {result}</Text>
</View>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ title: 'Examples' }}
/>
<Stack.Screen name="FAQ" component={Faq} />
{/* <Stack.Screen
name="Home"
component={Home}
options={{ title: 'Examples' }}
/> */}
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
71 changes: 71 additions & 0 deletions example/src/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from 'react';
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import type { StackNavigationProp } from '@react-navigation/stack';

import { Screen } from './Screen';

import { white, lightGrey, blue, lightPurple } from './colors';
import { ICON_SIZE } from './constants';
import type { StackParamList } from './types';

const examples: Array<{
name: keyof StackParamList;
label: string;
icon: string;
color: string;
}> = [
{
name: 'FAQ',
icon: 'frequently-asked-questions',
label: 'FAQ',
color: blue,
},
{
name: 'Card',
icon: 'card-text-outline',
label: 'Card',
color: lightPurple,
},
];

type Props = {
navigation: StackNavigationProp<StackParamList, 'Home'>;
};

export function Home({ navigation }: Props) {
return (
<View>
{examples.map(({ name, label, icon, color }) => (
<TouchableOpacity key={name} onPress={() => navigation.navigate(name)}>
<View style={styles.buttonInnerContainer}>
<MaterialCommunityIcons
style={styles.iconStyle}
name={icon}
color={color}
size={ICON_SIZE}
/>
<Text style={styles.labelStyle}>{label}</Text>
</View>
</TouchableOpacity>
))}
</View>
);
}

const styles = StyleSheet.create({
buttonInnerContainer: {
flexDirection: 'row',
alignItems: 'center',
padding: 10,
backgroundColor: white,
borderBottomColor: lightGrey,
borderBottomWidth: StyleSheet.hairlineWidth,
},
iconStyle: {
marginRight: 20,
},
labelStyle: {
fontSize: 18,
},
});
20 changes: 20 additions & 0 deletions example/src/Screen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';

// import { white } from './colors';

type Props = {
children: React.ReactNode;
};

export function Screen({ children }: Props) {
return <View style={styles.screen}>{children}</View>;
}

const styles = StyleSheet.create({
screen: {
flex: 1,
// backgroundColor: white,
padding: 16,
},
});
Binary file added example/src/assets/fonts/Montserrat-Bold.ttf
Binary file not shown.
Binary file added example/src/assets/fonts/Montserrat-Regular.ttf
Binary file not shown.
Binary file added example/src/assets/fonts/Montserrat-SemiBold.ttf
Binary file not shown.
Binary file added example/src/assets/fonts/OpenSans-Bold.ttf
Binary file not shown.
Binary file added example/src/assets/fonts/OpenSans-Regular.ttf
Binary file not shown.
Binary file added example/src/assets/fonts/OpenSans-SemiBold.ttf
Binary file not shown.
15 changes: 15 additions & 0 deletions example/src/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const lightBlue = '#34b2d9';
export const blue = '#0b6eb5';
export const green = '#0D8426';
export const lightGrey = '#d4d4d4';
export const darkGrey = '#666666';
export const white = '#ffffff';
export const red = '#fa5448';
export const lightPurple = '#a94af7';
export const pink = '#ff5ed4';
export const orange = '#ffc524';
export const brown = '#82630d';
export const darkBrown = '#362c13';
export const body = '#555C6B';
export const heading = '#2F3749';
export const black = '#000000';
4 changes: 4 additions & 0 deletions example/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const ICON_SIZE = 30;
export const HEADING_FONT_SIZE = 30;
export const QUESTION_FONT_SIZE = 14;
export const ANSWER_FONT_SIZE = 14;
Empty file added example/src/examples/card.tsx
Empty file.
80 changes: 80 additions & 0 deletions example/src/examples/faq/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { View, StyleSheet, StyleProp, ViewStyle, Text } from 'react-native';
import { useAccordionAnimation } from 'reanimated-accordion-helpers';

import { AnimatedAccordionSection } from './AnimatedAccordionSection';
import { AccordionButton } from './AccordionButton';
import { lightGrey, white, body, black } from '../../colors';
import { ANSWER_FONT_SIZE } from '../../constants';
import { OpenSans } from '../../fonts';

type Props = {
question: string;
answer: string;
style?: StyleProp<ViewStyle>;
};

export function Accordion({ question, answer, style }: Props) {
const {
animatedHeight,
height,
onPress,
onLayout,
state,
} = useAccordionAnimation();

return (
<View style={styles.shadow}>
<View style={[styles.container, style]}>
<AccordionButton
height={height}
animatedHeight={animatedHeight}
onButtonPress={onPress}
question={question}
expanded={state === 'expanded'}
/>
<AnimatedAccordionSection
animatedHeight={animatedHeight}
height={height}
onLayout={onLayout}
>
<View style={styles.answerContainer}>
<Text style={styles.answer}>{answer}</Text>
</View>
</AnimatedAccordionSection>
</View>
</View>
);
}

const styles = StyleSheet.create({
shadow: {
shadowColor: black,
shadowOffset: {
height: 1,
width: 0,
},
shadowRadius: 1,
shadowOpacity: 0.05,
elevation: 2,
},
container: {
backgroundColor: white,
overflow: 'hidden',
borderRadius: 6,
},
content: {
borderBottomWidth: 1,
borderBottomColor: lightGrey,
},
answerContainer: {
paddingHorizontal: 16,
paddingBottom: 16,
},
answer: {
fontFamily: OpenSans,
fontSize: ANSWER_FONT_SIZE,
color: body,
lineHeight: 20,
},
});
48 changes: 48 additions & 0 deletions example/src/examples/faq/AccordionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { View, TouchableWithoutFeedback, Text, StyleSheet } from 'react-native';
import type Animated from 'react-native-reanimated';

import { white, green } from '../../colors';
import { QUESTION_FONT_SIZE } from '../../constants';
import { MontserratSemiBold } from '../../fonts';

type Props = {
question: string;
onButtonPress: () => void;
height: number;
animatedHeight: Animated.Node<number>;
expanded: boolean;
};

export function AccordionButton({
question,
animatedHeight,
onButtonPress,
height,
expanded,
}: Props) {
return (
<TouchableWithoutFeedback
onPress={onButtonPress}
accessibilityRole="button"
accessibilityState={{ expanded }}
>
<View style={styles.container}>
<Text style={styles.question}>{question}?</Text>
</View>
</TouchableWithoutFeedback>
);
}

const styles = StyleSheet.create({
container: {
backgroundColor: white,
paddingVertical: 16,
paddingHorizontal: 16,
},
question: {
fontFamily: MontserratSemiBold,
fontSize: QUESTION_FONT_SIZE,
color: green,
},
});
66 changes: 66 additions & 0 deletions example/src/examples/faq/AnimatedAccordionSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import { LayoutChangeEvent, StyleSheet } from 'react-native';
import Animated, { Extrapolate } from 'react-native-reanimated';

const { interpolate } = Animated;

type Props = {
children: React.ReactNode;
onLayout: (event: LayoutChangeEvent) => void;
animatedHeight: Animated.Node<number>;
height: number;
};

export function AnimatedAccordionSection({
children,
onLayout,
animatedHeight,
height,
}: Props) {
/*
* Accordion section animation consists of few separate animations:
* 1. We Have a wrapping view (Container) that animates it's height from 0 to x (x is measuered with onLayout)
* 2. Container have a child - an absolutely positioned View with a property "top" set to 0.
* Thanks to that, when container height changes (animation runs), the absolutely positioned view appears.
* This approach lets us avoid situation where text is jumping, because it's height is being directly animated.
* 3. Opacity - we animate from 0 to 1 when expanding just to make the animation more smooth.
* 4. TranslateY - we animate from -15px to -5px when expanding just to make nice visual effect.
*/
return (
<Animated.View style={[{ height: animatedHeight }]}>
<Animated.View
onLayout={onLayout}
style={[
styles.container,
{
opacity: interpolate(animatedHeight, {
inputRange: [0, height],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
}),
transform: [
{
translateY: interpolate(animatedHeight, {
inputRange: [0, height],
outputRange: [-15, -5],
extrapolate: Extrapolate.CLAMP,
}),
},
],
},
]}
>
{children}
</Animated.View>
</Animated.View>
);
}

const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
});
Loading

0 comments on commit 15efdcc

Please sign in to comment.