Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: export page content props #21

Merged
merged 3 commits into from
Jun 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ const Screen = () => {

#### PaperOnboardingItemType

| name | description | required | type |
| ---------------- | --------------------------------------------------------------------------------------------- | -------- | ------------------------------------------ |
| content | Slide/page content, this will replace default content. | NO | (() => React.ReactNode) \| React.ReactNode |
| image | Image cover. | NO | (() => React.ReactNode) \| React.ReactNode |
| icon | Indicator icon. | NO | (() => React.ReactNode) \| React.ReactNode |
| backgroundColor | Background color. | YES | string |
| title | Title text. | NO | string |
| description | Description text. | NO | string |
| titleStyle | Text style to override page/slide title default style. | NO | StyleProp<TextStyle> |
| descriptionStyle | Text style to override page/slide description default style. | NO | StyleProp<TextStyle> |
| showCloseButton | Show close button when page/slide is active, _note: last page will always show close button._ | NO | boolean |
| name | description | required | type |
| ---------------- | --------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------- |
| content | Slide/page content, this will replace default content. | NO | ((props: [PageContentProps](./src/types.ts#L87)) => React.ReactNode) \| React.ReactNode |
| image | Image cover. | NO | (() => React.ReactNode) \| React.ReactNode |
| icon | Indicator icon. | NO | (() => React.ReactNode) \| React.ReactNode |
| backgroundColor | Background color. | YES | string |
| title | Title text. | NO | string |
| description | Description text. | NO | string |
| titleStyle | Text style to override page/slide title default style. | NO | StyleProp<TextStyle> |
| descriptionStyle | Text style to override page/slide description default style. | NO | StyleProp<TextStyle> |
| showCloseButton | Show close button when page/slide is active, _note: last page will always show close button._ | NO | boolean |

## Built With ❤️

Expand Down
86 changes: 77 additions & 9 deletions example/src/components/CustomView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import React from 'react';
import { View, Text, StyleSheet, Alert } from 'react-native';
import { View, Text, StyleSheet, Alert, ViewStyle } from 'react-native';
import Animated, { interpolate, Extrapolate } from 'react-native-reanimated';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { PageContentProps } from '@gorhom/paper-onboarding';
import { TouchableOpacityProps } from 'react-native';

const AnimatedTouchableOpacity: React.FC<Animated.AnimateProps<
ViewStyle,
TouchableOpacityProps
>> = Animated.createAnimatedComponent(TouchableOpacity) as any;

const styles = StyleSheet.create({
container: {
Expand Down Expand Up @@ -34,19 +42,79 @@ const styles = StyleSheet.create({
},
});

const CustomView = () => {
const CustomView = ({ animatedFocus }: PageContentProps) => {
//#region animations
const animatedBoxTranslateY = interpolate(animatedFocus, {
inputRange: [0, 1],
outputRange: [100, 0],
extrapolate: Extrapolate.CLAMP,
});
//#endregion

//#region styles
const boxStyle = [
styles.box,
{
transform: [
{ translateY: animatedBoxTranslateY },
] as Animated.AnimatedTransform,
},
];
const item1Style = [
styles.item,
{
opacity: interpolate(animatedFocus, {
inputRange: [0.5, 1],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
}),
},
];
const item2Style = [
styles.item,
{
opacity: interpolate(animatedFocus, {
inputRange: [0.625, 1],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
}),
},
];
const item3Style = [
styles.item2,
{
opacity: interpolate(animatedFocus, {
inputRange: [0.75, 1],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
}),
},
];
const buttonStyle = {
opacity: interpolate(animatedFocus, {
inputRange: [0.875, 1],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP,
}),
};
//#endregion

const handleButtonPress = () => {
Alert.alert('Button Clicked !');
};
return (
<View style={styles.container}>
<View style={styles.box} />
<View style={styles.item} />
<View style={styles.item} />
<View style={styles.item2} />
<TouchableOpacity onPress={handleButtonPress}>
<View
style={styles.container}
shouldRasterizeIOS={true}
needsOffscreenAlphaCompositing={true}
>
<Animated.View style={boxStyle} />
<Animated.View style={item1Style} />
<Animated.View style={item2Style} />
<Animated.View style={item3Style} />
<AnimatedTouchableOpacity style={buttonStyle} onPress={handleButtonPress}>
<Text style={styles.buttonText}>Button</Text>
</TouchableOpacity>
</AnimatedTouchableOpacity>
</View>
);
};
Expand Down
98 changes: 48 additions & 50 deletions src/components/page/Page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useMemo, useCallback, memo } from 'react';
import { Text } from 'react-native';
import { Svg, Circle } from 'react-native-svg';
import Animated from 'react-native-reanimated';
import { calculateRectangleCircleRadius } from '../../utils/math';
import PageContent from '../pageContent/PageContent';
import { PageProps } from '../../types';
import { styles } from './styles';

Expand Down Expand Up @@ -35,15 +35,20 @@ const PageComponent = ({
[screenDimensions, indicatorSize, safeInsets]
);

// animations
const animatedContentOpacity = interpolate(currentIndex, {
inputRange: [index - 0.5, index, index + 0.5],
//#region animation
const animatedFocus = interpolate(currentIndex, {
inputRange: [index - 1, index, index + 1],
outputRange: [0, 1, 2],
extrapolate: Extrapolate.CLAMP,
});
const animatedContentOpacity = interpolate(animatedFocus, {
inputRange: [0.5, 1, 1.5],
outputRange: [0, 1, 0],
extrapolate: Extrapolate.CLAMP,
});

const animatedContentTopPosition = interpolate(currentIndex, {
inputRange: [index - 1, index, index + 1],
const animatedContentTopPosition = interpolate(animatedFocus, {
inputRange: [0, 1, 2],
outputRange: [
screenDimensions.height / 8,
0,
Expand All @@ -52,14 +57,8 @@ const PageComponent = ({
extrapolate: Extrapolate.CLAMP,
});

const animatedImageTopPosition = interpolate(currentIndex, {
inputRange: [index - 1, index],
outputRange: [screenDimensions.height / 8, 0],
extrapolate: Extrapolate.CLAMP,
});

const animatedBackgroundSize = interpolate(currentIndex, {
inputRange: [index - 1, index],
const animatedBackgroundSize = interpolate(animatedFocus, {
inputRange: [0, 1],
outputRange: [0, backgroundExtendedSize],
extrapolate: Extrapolate.CLAMP,
});
Expand All @@ -69,8 +68,9 @@ const PageComponent = ({
indicatorSize / 2,
index * indicatorSize
);
//#endregion

// styles
//#region styles
const contentContainerStyle: any = useMemo(
() => [
styles.contentContainer,
Expand All @@ -90,40 +90,54 @@ const PageComponent = ({
indicatorSize,
]
);

const titleStyle = useMemo(
() => [
styles.title,
titleStyleOverride,
item.titleStyle ? item.titleStyle : null,
],
() => [titleStyleOverride, item.titleStyle ? item.titleStyle : null],
[item, titleStyleOverride]
);

const descriptionStyle = useMemo(
() => [
styles.description,
descriptionStyleOverride,
item.descriptionStyle ? item.descriptionStyle : null,
],
[item, descriptionStyleOverride]
);
//#endregion

const imageContainerStyle: any = useMemo(
() => [
styles.imageContainer,
{
transform: [{ translateY: animatedImageTopPosition }],
},
],
[animatedImageTopPosition]
);

//#region callbacks
const handleContainerRef = useCallback(ref => handleRef(ref, index), [
index,
handleRef,
]);
//#endregion

//#region memo
const pageContentProps = useMemo(
() => ({
index,
animatedFocus,
image: item.image,
title: item.title,
description: item.description,
titleStyle,
descriptionStyle,
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[index, item, titleStyle, descriptionStyle]
);
//#endregion

const renderContent = useCallback(() => {
const ContentComponent: any = item.content;
return ContentComponent ? (
typeof ContentComponent === 'function' ? (
ContentComponent(pageContentProps)
) : (
<ContentComponent {...pageContentProps} />
)
) : (
<PageContent {...pageContentProps} />
);
}, [item, pageContentProps]);
return (
<Animated.View
pointerEvents={index === 0 ? 'auto' : 'none'}
Expand All @@ -141,23 +155,7 @@ const PageComponent = ({
/>
</Svg>
<Animated.View style={contentContainerStyle}>
{item.content ? (
typeof item.content === 'function' ? (
item.content()
) : (
item.content
)
) : (
<>
{item.image && (
<Animated.View style={imageContainerStyle}>
{typeof item.image === 'function' ? item.image() : item.image}
</Animated.View>
)}
<Text style={titleStyle}>{item.title}</Text>
<Text style={descriptionStyle}>{item.description}</Text>
</>
)}
{renderContent()}
</Animated.View>
</Animated.View>
);
Expand Down
17 changes: 0 additions & 17 deletions src/components/page/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,6 @@ export const styles = StyleSheet.create({
justifyContent: 'center',
paddingHorizontal: 34,
},
imageContainer: {
overflow: 'hidden',
marginBottom: 64,
},
title: {
textAlign: 'center',
color: 'white',
fontWeight: '600',
fontSize: 36,
marginBottom: 16,
},
description: {
color: 'white',
textAlign: 'center',
fontWeight: '400',
fontSize: 18,
},
background: {
...StyleSheet.absoluteFillObject,
},
Expand Down
62 changes: 62 additions & 0 deletions src/components/pageContent/PageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useMemo, memo } from 'react';
import { Text, Dimensions } from 'react-native';
import Animated from 'react-native-reanimated';
import { PageContentProps } from '../../types';
import { styles } from './styles';

const { interpolate, Extrapolate } = Animated;

const SCREEN_HEIGHT = Dimensions.get('window').height;

const PageContentComponent = ({
animatedFocus,
image,
title,
description,
titleStyle: titleStyleOverride,
descriptionStyle: descriptionStyleOverride,
}: PageContentProps) => {
//#region
const animatedImageTopPosition = interpolate(animatedFocus, {
inputRange: [0, 1],
outputRange: [SCREEN_HEIGHT / 8, 0],
extrapolate: Extrapolate.CLAMP,
});
//#endregion

//#region styles
const titleStyle = useMemo(() => [styles.title, titleStyleOverride], [
titleStyleOverride,
]);

const descriptionStyle = useMemo(
() => [styles.description, descriptionStyleOverride],
[descriptionStyleOverride]
);

const imageContainerStyle: any = useMemo(
() => [
styles.imageContainer,
{
transform: [{ translateY: animatedImageTopPosition }],
},
],
[animatedImageTopPosition]
);
//#endregion
return (
<>
{image && (
<Animated.View style={imageContainerStyle}>
{typeof image === 'function' ? image() : image}
</Animated.View>
)}
<Text style={titleStyle}>{title}</Text>
<Text style={descriptionStyle}>{description}</Text>
</>
);
};

const PageContent = memo(PageContentComponent);

export default PageContent;
Empty file.
Loading