react-native-app-onboard 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +187 -0
  3. package/lib/commonjs/components/CustomPages.js +134 -0
  4. package/lib/commonjs/components/CustomPages.js.map +1 -0
  5. package/lib/commonjs/components/OnboardingPages.js +157 -0
  6. package/lib/commonjs/components/OnboardingPages.js.map +1 -0
  7. package/lib/commonjs/components/Page.js +60 -0
  8. package/lib/commonjs/components/Page.js.map +1 -0
  9. package/lib/commonjs/components/Pagination.js +94 -0
  10. package/lib/commonjs/components/Pagination.js.map +1 -0
  11. package/lib/commonjs/components/Swiper.js +56 -0
  12. package/lib/commonjs/components/Swiper.js.map +1 -0
  13. package/lib/commonjs/components/button.js +57 -0
  14. package/lib/commonjs/components/button.js.map +1 -0
  15. package/lib/commonjs/components/index.js +17 -0
  16. package/lib/commonjs/components/index.js.map +1 -0
  17. package/lib/commonjs/context/OnboardingContext.js +65 -0
  18. package/lib/commonjs/context/OnboardingContext.js.map +1 -0
  19. package/lib/commonjs/hooks/useOnboarding.js +18 -0
  20. package/lib/commonjs/hooks/useOnboarding.js.map +1 -0
  21. package/lib/commonjs/index.js +26 -0
  22. package/lib/commonjs/index.js.map +1 -0
  23. package/lib/commonjs/types/index.js +6 -0
  24. package/lib/commonjs/types/index.js.map +1 -0
  25. package/lib/module/components/CustomPages.js +126 -0
  26. package/lib/module/components/CustomPages.js.map +1 -0
  27. package/lib/module/components/OnboardingPages.js +147 -0
  28. package/lib/module/components/OnboardingPages.js.map +1 -0
  29. package/lib/module/components/Page.js +53 -0
  30. package/lib/module/components/Page.js.map +1 -0
  31. package/lib/module/components/Pagination.js +87 -0
  32. package/lib/module/components/Pagination.js.map +1 -0
  33. package/lib/module/components/Swiper.js +48 -0
  34. package/lib/module/components/Swiper.js.map +1 -0
  35. package/lib/module/components/button.js +49 -0
  36. package/lib/module/components/button.js.map +1 -0
  37. package/lib/module/components/index.js +2 -0
  38. package/lib/module/components/index.js.map +1 -0
  39. package/lib/module/context/OnboardingContext.js +57 -0
  40. package/lib/module/context/OnboardingContext.js.map +1 -0
  41. package/lib/module/hooks/useOnboarding.js +10 -0
  42. package/lib/module/hooks/useOnboarding.js.map +1 -0
  43. package/lib/module/index.js +13 -0
  44. package/lib/module/index.js.map +1 -0
  45. package/lib/module/types/index.js +2 -0
  46. package/lib/module/types/index.js.map +1 -0
  47. package/lib/typescript/src/components/CustomPages.d.ts +21 -0
  48. package/lib/typescript/src/components/CustomPages.d.ts.map +1 -0
  49. package/lib/typescript/src/components/OnboardingPages.d.ts +15 -0
  50. package/lib/typescript/src/components/OnboardingPages.d.ts.map +1 -0
  51. package/lib/typescript/src/components/Page.d.ts +17 -0
  52. package/lib/typescript/src/components/Page.d.ts.map +1 -0
  53. package/lib/typescript/src/components/Pagination.d.ts +29 -0
  54. package/lib/typescript/src/components/Pagination.d.ts.map +1 -0
  55. package/lib/typescript/src/components/Swiper.d.ts +4 -0
  56. package/lib/typescript/src/components/Swiper.d.ts.map +1 -0
  57. package/lib/typescript/src/components/button.d.ts +12 -0
  58. package/lib/typescript/src/components/button.d.ts.map +1 -0
  59. package/lib/typescript/src/components/index.d.ts +2 -0
  60. package/lib/typescript/src/components/index.d.ts.map +1 -0
  61. package/lib/typescript/src/context/OnboardingContext.d.ts +28 -0
  62. package/lib/typescript/src/context/OnboardingContext.d.ts.map +1 -0
  63. package/lib/typescript/src/hooks/useOnboarding.d.ts +12 -0
  64. package/lib/typescript/src/hooks/useOnboarding.d.ts.map +1 -0
  65. package/lib/typescript/src/index.d.ts +5 -0
  66. package/lib/typescript/src/index.d.ts.map +1 -0
  67. package/lib/typescript/src/types/index.d.ts +42 -0
  68. package/lib/typescript/src/types/index.d.ts.map +1 -0
  69. package/package.json +160 -0
  70. package/src/components/CustomPages.tsx +160 -0
  71. package/src/components/OnboardingPages.tsx +173 -0
  72. package/src/components/Page.tsx +90 -0
  73. package/src/components/Pagination.tsx +151 -0
  74. package/src/components/Swiper.tsx +56 -0
  75. package/src/components/button.tsx +74 -0
  76. package/src/components/index.ts +1 -0
  77. package/src/context/OnboardingContext.tsx +95 -0
  78. package/src/hooks/useOnboarding.tsx +12 -0
  79. package/src/index.tsx +18 -0
  80. package/src/types/index.ts +40 -0
@@ -0,0 +1,90 @@
1
+ import {
2
+ View,
3
+ Text,
4
+ StyleSheet,
5
+ Dimensions,
6
+ type StyleProp,
7
+ type ViewStyle,
8
+ type TextStyle,
9
+ } from 'react-native';
10
+ import React from 'react';
11
+
12
+ export type Page = {
13
+ title: string;
14
+ subtitle: string;
15
+ image: React.ReactNode;
16
+ backgroundColor: string;
17
+ color?: string;
18
+ width?: number;
19
+ containerStyle?: StyleProp<ViewStyle>;
20
+ imageContainerStyle?: StyleProp<ViewStyle>;
21
+ titleContainerStyle?: StyleProp<ViewStyle>;
22
+ titleStyle?: StyleProp<TextStyle>;
23
+ subtitleStyle?: StyleProp<TextStyle>;
24
+ };
25
+
26
+ const { width, height } = Dimensions.get('window');
27
+ const potrait = height > width;
28
+
29
+ export function OnboardingPage(props: Page) {
30
+ return (
31
+ <View
32
+ style={[styles.container, { width: props.width }, props.containerStyle]}
33
+ >
34
+ <View style={[styles.imageContainer, props.imageContainerStyle]}>
35
+ {props.image}
36
+ </View>
37
+ <View style={[styles.titleContainer, props.titleContainerStyle]}>
38
+ <Text
39
+ style={[
40
+ styles.title,
41
+ {
42
+ color: props.color,
43
+ },
44
+ props.titleStyle,
45
+ ]}
46
+ >
47
+ {props.title}
48
+ </Text>
49
+ <Text
50
+ style={[
51
+ styles.subtitle,
52
+ {
53
+ color: props.color,
54
+ },
55
+ props.subtitleStyle,
56
+ ]}
57
+ >
58
+ {props.subtitle}
59
+ </Text>
60
+ </View>
61
+ </View>
62
+ );
63
+ }
64
+
65
+ const styles = StyleSheet.create({
66
+ container: {
67
+ flex: 1,
68
+ justifyContent: 'center',
69
+ alignItems: 'center',
70
+ },
71
+ title: {
72
+ fontSize: 24,
73
+ fontWeight: 'bold',
74
+ paddingBottom: 15,
75
+ textAlign: 'center',
76
+ },
77
+ subtitle: {
78
+ fontSize: 18,
79
+ textAlign: 'center',
80
+ },
81
+ imageContainer: {
82
+ flex: 0,
83
+ paddingBottom: potrait ? 60 : 10,
84
+ alignItems: 'center',
85
+ width: '100%',
86
+ },
87
+ titleContainer: {
88
+ marginHorizontal: 30,
89
+ },
90
+ });
@@ -0,0 +1,151 @@
1
+ import {
2
+ View,
3
+ Animated,
4
+ StyleSheet,
5
+ type StyleProp,
6
+ type ViewStyle,
7
+ type TextStyle,
8
+ } from 'react-native';
9
+ import React from 'react';
10
+ import { useOnboarding } from '../hooks/useOnboarding';
11
+ import { Button } from './button';
12
+
13
+ type FooterProps = {
14
+ animatedValue: Animated.Value;
15
+ numberOfScreens: number;
16
+ backgroundColor: string;
17
+ color: string;
18
+ width: number;
19
+ showDone?: boolean;
20
+ showSkip?: boolean;
21
+ showNext?: boolean;
22
+ nextLabel?: string | React.ReactNode;
23
+ skipLabel?: string | React.ReactNode;
24
+ doneLabel?: string | React.ReactNode;
25
+ paginationContainerStyle?: StyleProp<ViewStyle>;
26
+ buttonRightContainerStyle?: StyleProp<ViewStyle>;
27
+ buttonLeftContainerStyle?: StyleProp<ViewStyle>;
28
+ dotsContainerStyle?: StyleProp<ViewStyle>;
29
+ doneLabelStyle?: StyleProp<TextStyle>;
30
+ skipLabelStyle?: StyleProp<TextStyle>;
31
+ nextLabelStyle?: StyleProp<TextStyle>;
32
+ paginationPosition?: 'top' | 'bottom';
33
+ onDone?: () => void;
34
+ onSkip?: () => void;
35
+ onNext?: () => void;
36
+ };
37
+
38
+ export function Pagination(props: FooterProps) {
39
+ const { isDone } = useOnboarding();
40
+ const dots = Array.from({ length: props.numberOfScreens }, (_, i) => i);
41
+ const width = props.width;
42
+ return (
43
+ <View
44
+ style={[
45
+ styles.pagination,
46
+ {
47
+ backgroundColor: props.backgroundColor,
48
+ },
49
+ props.paginationContainerStyle,
50
+ ]}
51
+ >
52
+ <View
53
+ style={[
54
+ styles.buttons,
55
+ styles.leftButton,
56
+ props.buttonLeftContainerStyle,
57
+ ]}
58
+ >
59
+ {props.showSkip && (
60
+ <Button
61
+ onPress={props.onSkip}
62
+ buttonTextStyle={props.skipLabelStyle}
63
+ label={props.skipLabel || 'Skip'}
64
+ />
65
+ )}
66
+ </View>
67
+ <View style={styles.dotsContainer}>
68
+ {dots.map((_, i) => {
69
+ const inputRange = [(i - 1) * width, i * width, (i + 1) * width];
70
+ const dotOpacity = props.animatedValue.interpolate({
71
+ inputRange,
72
+ outputRange: [0.3, 1, 0.3],
73
+ extrapolate: 'clamp',
74
+ });
75
+ return (
76
+ <Animated.View
77
+ key={i}
78
+ style={[
79
+ styles.dot,
80
+ {
81
+ backgroundColor: props.color,
82
+ opacity: dotOpacity,
83
+ },
84
+ props.dotsContainerStyle,
85
+ ]}
86
+ />
87
+ );
88
+ })}
89
+ </View>
90
+ <View
91
+ style={[
92
+ styles.buttons,
93
+ styles.rightButton,
94
+ props.buttonRightContainerStyle,
95
+ ]}
96
+ >
97
+ {!isDone && props.showNext && (
98
+ <Button
99
+ onPress={props.onNext}
100
+ label={props.nextLabel || 'Next'}
101
+ buttonTextStyle={props.nextLabelStyle}
102
+ />
103
+ )}
104
+ {isDone && props.showDone && (
105
+ <Button
106
+ onPress={props.onDone}
107
+ label={props.doneLabel || 'Done'}
108
+ buttonTextStyle={props.doneLabelStyle}
109
+ />
110
+ )}
111
+ </View>
112
+ </View>
113
+ );
114
+ }
115
+
116
+ const styles = StyleSheet.create({
117
+ pagination: {
118
+ flexDirection: 'row',
119
+ justifyContent: 'space-between',
120
+ alignItems: 'center',
121
+ height: 60,
122
+ paddingVertical: 10,
123
+ paddingHorizontal: 20,
124
+ },
125
+ dot: {
126
+ height: 10,
127
+ width: 10,
128
+ borderRadius: 5,
129
+ backgroundColor: 'blue',
130
+ marginHorizontal: 8,
131
+ },
132
+ dotsContainer: {
133
+ flexDirection: 'row',
134
+ flex: 1,
135
+ justifyContent: 'center',
136
+ },
137
+ text: {
138
+ fontSize: 16,
139
+ },
140
+ buttons: {
141
+ minWidth: 200,
142
+ },
143
+ rightButton: {
144
+ alignItems: 'flex-end',
145
+ paddingRight: 30,
146
+ },
147
+ leftButton: {
148
+ alignItems: 'flex-start',
149
+ paddingLeft: 30,
150
+ },
151
+ });
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { OnboardingPages } from './OnboardingPages';
3
+ import { CustomPages } from './CustomPages';
4
+ import { Animated } from 'react-native';
5
+ import { useOnboarding } from '../hooks/useOnboarding';
6
+ import type { OnboardingProps } from '../types';
7
+
8
+ export const Swiper: React.FC<OnboardingProps> = (props) => {
9
+ const scrollX = React.useRef(new Animated.Value(0)).current;
10
+ const {
11
+ flatListRef,
12
+ setCurrentPage,
13
+ currentPage,
14
+ numberOfScreens,
15
+ nextPage,
16
+ scrollEnabled,
17
+ } = useOnboarding();
18
+ if (props.children) {
19
+ return (
20
+ <CustomPages
21
+ customFooter={props.customFooter}
22
+ showPagination={props.showPagination}
23
+ flatListRef={flatListRef}
24
+ scrollX={scrollX}
25
+ setPage={setCurrentPage}
26
+ scrollEnabled={scrollEnabled}
27
+ currentPage={currentPage}
28
+ numberOfScreens={numberOfScreens}
29
+ nextPage={nextPage}
30
+ showDone={props.showDone}
31
+ onDone={props.onDone}
32
+ >
33
+ {props.children}
34
+ </CustomPages>
35
+ );
36
+ }
37
+
38
+ return (
39
+ <OnboardingPages
40
+ showDone={props.showDone}
41
+ customFooter={props.customFooter}
42
+ flatListRef={flatListRef}
43
+ scrollX={scrollX}
44
+ setPage={setCurrentPage}
45
+ currentPage={currentPage}
46
+ paginationPosition={props.paginationPosition}
47
+ nextPage={nextPage}
48
+ showSkip={props.showSkip}
49
+ onDone={props.onDone}
50
+ pages={props.pages || []}
51
+ width={props.width}
52
+ color={props.color}
53
+ onSkip={props.onSkip}
54
+ />
55
+ );
56
+ };
@@ -0,0 +1,74 @@
1
+ import {
2
+ StyleSheet,
3
+ Text,
4
+ TouchableOpacity,
5
+ type StyleProp,
6
+ type TextStyle,
7
+ type ViewStyle,
8
+ } from 'react-native';
9
+ import React from 'react';
10
+
11
+ type ButtonProps = {
12
+ onPress?: () => void;
13
+ label?: string | React.ReactNode;
14
+ color?: string;
15
+ buttonStyle?: StyleProp<ViewStyle>;
16
+ buttonTextStyle?: StyleProp<TextStyle>;
17
+ };
18
+
19
+ export const Button = (props: ButtonProps) => {
20
+ return typeof props.label === 'string' ? (
21
+ <TouchableOpacity onPress={props.onPress} style={props.buttonStyle}>
22
+ <Text
23
+ style={[
24
+ styles.text,
25
+ {
26
+ color: props.color || 'white',
27
+ },
28
+ props.buttonTextStyle,
29
+ ]}
30
+ >
31
+ {props.label}
32
+ </Text>
33
+ </TouchableOpacity>
34
+ ) : (
35
+ props.label
36
+ );
37
+ };
38
+
39
+ const styles = StyleSheet.create({
40
+ pagination: {
41
+ flexDirection: 'row',
42
+ justifyContent: 'space-between',
43
+ alignItems: 'center',
44
+ height: 60,
45
+ paddingVertical: 10,
46
+ paddingHorizontal: 20,
47
+ },
48
+ dot: {
49
+ height: 10,
50
+ width: 10,
51
+ borderRadius: 5,
52
+ backgroundColor: 'blue',
53
+ marginHorizontal: 8,
54
+ },
55
+ dotsContainer: {
56
+ flexDirection: 'row',
57
+ flex: 1,
58
+ justifyContent: 'center',
59
+ },
60
+ text: {
61
+ fontSize: 16,
62
+ },
63
+ buttons: {
64
+ minWidth: 200,
65
+ },
66
+ rightButton: {
67
+ alignItems: 'flex-end',
68
+ paddingRight: 30,
69
+ },
70
+ leftButton: {
71
+ alignItems: 'flex-start',
72
+ paddingLeft: 30,
73
+ },
74
+ });
@@ -0,0 +1 @@
1
+ export * from './Swiper';
@@ -0,0 +1,95 @@
1
+ import React from 'react';
2
+ import { Dimensions, type FlatList } from 'react-native';
3
+
4
+ export type SliderProps = {
5
+ currentPage: number;
6
+ numberOfScreens: number;
7
+ nextPage: (animated?: boolean) => void;
8
+ scrollTo: (index: number, animated?: boolean) => void;
9
+ };
10
+
11
+ type OnboardingContextType = SliderProps & {
12
+ setCurrentPage: (index: number) => void;
13
+ flatListRef: React.RefObject<FlatList>;
14
+ width?: number;
15
+ numberOfScreens: number;
16
+ progress: number;
17
+ scrollEnabled?: boolean;
18
+ enableScroll: React.Dispatch<React.SetStateAction<boolean | undefined>>;
19
+ isDone: boolean;
20
+ };
21
+
22
+ type OnboardingProviderProps = {
23
+ children: React.ReactNode;
24
+ width?: number;
25
+ numberOfScreens: number;
26
+ scrollEnabled?: boolean;
27
+ };
28
+
29
+ export const OnboardingContext = React.createContext<
30
+ OnboardingContextType | undefined
31
+ >(undefined);
32
+
33
+ export const OnboardingProvider: React.FC<OnboardingProviderProps> = ({
34
+ children,
35
+ width = Dimensions.get('window').width,
36
+ numberOfScreens,
37
+ scrollEnabled,
38
+ }) => {
39
+ const getProgress = (page: number) => {
40
+ return Math.round(((page + 1) / numberOfScreens) * 100);
41
+ };
42
+
43
+ const [currentPage, setPage] = React.useState(0);
44
+ const [progress, setProgress] = React.useState(getProgress(0));
45
+ const [isDone, setIsDone] = React.useState(false);
46
+ const [enableScroll, setEnableScroll] = React.useState<boolean | undefined>(
47
+ scrollEnabled
48
+ );
49
+ const flatListRef = React.useRef<FlatList>(null);
50
+
51
+ const setCurrentPage = (index: number) => {
52
+ setPage(index);
53
+ setProgress(getProgress(index));
54
+ setIsDone(index === numberOfScreens - 1);
55
+ };
56
+
57
+ const nextPage = (animated: boolean = true) => {
58
+ if (flatListRef.current) {
59
+ flatListRef.current.scrollToOffset({
60
+ offset: width * (currentPage + 1),
61
+ animated: animated,
62
+ });
63
+ }
64
+ setCurrentPage(currentPage + 1);
65
+ };
66
+
67
+ const scrollTo = (index: number, animated: boolean = true) => {
68
+ if (flatListRef.current && index >= 0) {
69
+ flatListRef.current.scrollToOffset({
70
+ offset: index * width,
71
+ animated: animated,
72
+ });
73
+ setCurrentPage(index);
74
+ }
75
+ };
76
+
77
+ const contextValue: OnboardingContextType = {
78
+ scrollEnabled: enableScroll,
79
+ enableScroll: setEnableScroll,
80
+ currentPage,
81
+ numberOfScreens,
82
+ nextPage,
83
+ setCurrentPage,
84
+ flatListRef,
85
+ scrollTo,
86
+ progress,
87
+ isDone,
88
+ };
89
+
90
+ return (
91
+ <OnboardingContext.Provider value={contextValue}>
92
+ {children}
93
+ </OnboardingContext.Provider>
94
+ );
95
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { OnboardingContext } from '../context/OnboardingContext';
3
+
4
+ export const useOnboarding = () => {
5
+ const context = React.useContext(OnboardingContext);
6
+ if (!context) {
7
+ throw new Error(
8
+ 'useOnboardingContext must be used within an OnboardingProvider'
9
+ );
10
+ }
11
+ return context;
12
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { Swiper } from './components/Swiper';
3
+ import { OnboardingProvider } from './context/OnboardingContext';
4
+ import type { OnboardingProps } from './types';
5
+
6
+ export { useOnboarding } from './hooks/useOnboarding';
7
+
8
+ export function Onboarding(props: OnboardingProps) {
9
+ const numberOfScreens = React.Children.count(props.children);
10
+ return (
11
+ <OnboardingProvider
12
+ scrollEnabled={props.scrollEnabled}
13
+ numberOfScreens={numberOfScreens || props.pages?.length || 0}
14
+ >
15
+ <Swiper {...props}>{props.children}</Swiper>
16
+ </OnboardingProvider>
17
+ );
18
+ }
@@ -0,0 +1,40 @@
1
+ import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
2
+ import type { Page } from '../components/Page';
3
+
4
+ export type OnboardingProps = {
5
+ children?: React.ReactNode[];
6
+ nextLabel?: string | React.ReactNode;
7
+ skipLabel?: string | React.ReactNode;
8
+ doneLabel?: string | React.ReactNode;
9
+ showSkip?: boolean;
10
+ showNext?: boolean;
11
+ showDone?: boolean;
12
+ onDone?: () => void;
13
+ onSkip?: () => void;
14
+ showPagination?: boolean;
15
+ scrollEnabled?: boolean;
16
+ customFooter?: (props: { nextPage: () => void }) => React.ReactNode;
17
+ paginationContainerStyle?: StyleProp<ViewStyle>;
18
+ buttonRightContainerStyle?: StyleProp<ViewStyle>;
19
+ buttonLeftContainerStyle?: StyleProp<ViewStyle>;
20
+ dotsContainerStyle?: StyleProp<ViewStyle>;
21
+ doneLabelStyle?: StyleProp<TextStyle>;
22
+ skipLabelStyle?: StyleProp<TextStyle>;
23
+ nextLabelStyle?: StyleProp<TextStyle>;
24
+ containerStyle?: StyleProp<ViewStyle>;
25
+ imageContainerStyle?: StyleProp<ViewStyle>;
26
+ titleContainerStyle?: StyleProp<ViewStyle>;
27
+ titleStyle?: StyleProp<TextStyle>;
28
+ subtitleStyle?: StyleProp<TextStyle>;
29
+ paginationPosition?: 'top' | 'bottom';
30
+ scrollAnimationDuration?: number;
31
+ useNativeDriver?: boolean;
32
+ width?: number;
33
+ color?: string;
34
+ pages?: Page[];
35
+ } & (
36
+ | {
37
+ children?: React.ReactNode[];
38
+ }
39
+ | { pages: Page[] }
40
+ );