├── .eslintrc
├── .gitignore
├── README.md
├── index.js
└── package.json
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "rules": {
4 | "import/no-extraneous-dependencies": 0,
5 | "import/no-unresolved": 0,
6 | "import/extensions": 0,
7 | "no-use-before-define": 0,
8 | "react/jsx-filename-extension": 0
9 | }
10 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | npm-debug.log
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Modal WalkThrough
2 | A modal to walk through different steps in react native
3 |
4 | ## Installation
5 | Install with yarn or npm
6 | ```
7 | yarn add react-native-modal-walk-through
8 | ```
9 |
10 | Import the lib
11 | ```
12 | import ModalWalkThrough from 'react-native-modal-walk-through';
13 | ```
14 |
15 | Add scenes
16 | ```
17 |
20 | {['scene1', 'scene2'].map(scene => (
21 |
22 | {scene}
23 |
24 | ))}
25 |
26 | ```
27 |
28 | ## Preview
29 | 
30 |
31 | ## Properties
32 | |Property |Type |Description |Default value |
33 | |---------|-----------|--------------------------------|--------------------|
34 | |height |Number |Height of the walkthrough |40% of screen height|
35 | |width |Number |Width of the walkthrough |80% of screen width |
36 | |onFinish |Function |When the user went throught the entire walkthrough| |
37 | |onStepChange|Function |When the user swiped to another step | |
38 |
39 | ## Methods
40 | ### goToStep (step: Number)
41 | Go to a particular step in the walkthrough,
42 | in case the number is bigger than the last step index, it will close the modal
43 |
44 | ### show
45 | Show the modal
46 |
47 | ### hide
48 | Hide the modal
49 |
50 | [](https://www.gitcheese.com/donate/users/5782495/repos/93313202)
51 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | Modal,
5 | FlatList,
6 | View,
7 | Dimensions,
8 | StyleSheet,
9 | BackHandler,
10 | BackAndroid,
11 | TouchableWithoutFeedback,
12 | } from 'react-native';
13 |
14 | /**
15 | *
16 | *
17 | * @returs {React.Component}
18 | */
19 | class ModalWalkThrough extends Component {
20 | static get propTypes() {
21 | return {
22 | height: PropTypes.number,
23 | width: PropTypes.number,
24 | onStepChange: PropTypes.func,
25 | onFinish: PropTypes.func,
26 | children: PropTypes.children,
27 | };
28 | }
29 |
30 | static get defaultProps() {
31 | return {
32 | height: null,
33 | width: null,
34 | onStepChange: null,
35 | onFinish: null,
36 | children: null,
37 | };
38 | }
39 |
40 | /**
41 | * Get the actual window height in pixels
42 | * @returns {Number} value in px
43 | */
44 | static get screenHeight() {
45 | return Dimensions.get('window').height;
46 | }
47 |
48 | /**
49 | * Get the actual window width in pixels
50 | * @returns {Number} value in px
51 | */
52 | static get screenWidth() {
53 | return Dimensions.get('window').width;
54 | }
55 |
56 |
57 | constructor() {
58 | super();
59 |
60 | this.goToStep = this.goToStep.bind(this);
61 | this.handleScroll = this.handleScroll.bind(this);
62 | this.handleHardwareBackPress = this.handleHardwareBackPress.bind(this);
63 | this.show = this.show.bind(this);
64 | this.hide = this.hide.bind(this);
65 | this.renderChild = this.renderChild.bind(this);
66 | }
67 |
68 | componentWillMount() {
69 | this.state = {
70 | visible: false,
71 | };
72 | }
73 |
74 | componentDidMount() {
75 | if (
76 | BackHandler &&
77 | typeof BackHandler.addEventListener === 'function'
78 | ) {
79 | BackHandler.addEventListener('hardwareBackPress', this.handleHardwareBackPress);
80 | } else {
81 | BackAndroid.addEventListener('hardwareBackPress', this.handleHardwareBackPress);
82 | }
83 | }
84 |
85 | componentWillUnmount() {
86 | if (
87 | BackHandler &&
88 | typeof BackHandler.addEventListener === 'function'
89 | ) {
90 | BackHandler.removeEventListener('hardwareBackPress', this.handleHardwareBackPress);
91 | } else {
92 | BackAndroid.removeEventListener('hardwareBackPress', this.handleHardwareBackPress);
93 | }
94 | }
95 |
96 | /**
97 | * Height of the scene
98 | * @return {Number|String} the height value
99 | */
100 | get height() {
101 | return this.props.height || '40%';
102 | }
103 |
104 | /**
105 | * Width of the scene
106 | * @return {Number|String} the width value
107 | */
108 | get width() {
109 | return this.props.width || (ModalWalkThrough.screenWidth * 0.8);
110 | }
111 |
112 | /**
113 | * Go to a specific step in the walkthrough
114 | * @param {Number} [index=0] the index to scroll to
115 | * @returns {void}
116 | */
117 | goToStep(index = 0) {
118 | if (index > this.props.children.length - 1) {
119 | // In case of going beyond last step, close the modal
120 | this.setState({ visible: false });
121 |
122 | // Trigger onFinish in case defined
123 | if (typeof this.props.onFinish === 'function') {
124 | this.props.onFinish();
125 | }
126 | } else {
127 | // Scroll the walkthrough to a specific step
128 | this.flatList.scrollToOffset({
129 | animated: true,
130 | offset: index * ModalWalkThrough.screenWidth,
131 | });
132 | }
133 | }
134 |
135 | /**
136 | * Handle user scroll event
137 | * @param {Object} eventData
138 | * @returns {void}
139 | */
140 | handleScroll(eventData) {
141 | // Only when onStepChange was defined
142 | if (typeof this.props.onStepChange === 'function') {
143 | const { x } = eventData.nativeEvent.contentOffset;
144 | const step = Math.round(x / ModalWalkThrough.screenWidth);
145 |
146 | // Trigger an onStepChange event with the current step
147 | this.props.onStepChange(step);
148 | }
149 | }
150 |
151 | /**
152 | * Handle a press on the physical back button (Android, tvOS)
153 | * @returns {void}
154 | */
155 | handleHardwareBackPress() {
156 | this.hide();
157 | }
158 |
159 | /**
160 | * Make the modal visible
161 | * @returns {void}
162 | */
163 | show() {
164 | this.setState({ visible: true });
165 | }
166 |
167 | /**
168 | * Make the modal invisible
169 | * @returns {void}
170 | */
171 | hide() {
172 | this.setState({ visible: false });
173 | }
174 |
175 | /**
176 | * Render child of the walkThrough
177 | * @param {Object} param0 Options param
178 | * @param {Object} param0.item Item component to render
179 | * @param {Nummber} param0.index Index of component
180 | * @returns {React.Component} component
181 | */
182 | renderChild({ item, index }) {
183 | return (
184 |
190 |
194 | {item}
195 |
196 |
197 | );
198 | }
199 |
200 | render() {
201 | return (
202 |
207 |
210 |
213 | { this.flatList = flatList; }}
220 | onScroll={this.handleScroll}
221 | bounces={false}
222 | />
223 |
224 |
225 |
226 | );
227 | }
228 | }
229 |
230 | const styles = StyleSheet.create({
231 | overlay: {
232 | backgroundColor: 'rgba(0,0,0,0.8)',
233 | flex: 1,
234 | },
235 | sceneWrapper: {
236 | alignItems: 'center',
237 | justifyContent: 'center',
238 | },
239 | scene: {
240 | backgroundColor: '#ffffff',
241 | borderRadius: 3,
242 | },
243 | });
244 |
245 | export default ModalWalkThrough;
246 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-modal-walk-through",
3 | "version": "0.1.5",
4 | "description": "Walkthrough in a React Native modal",
5 | "main": "index.js",
6 | "repository": "http://github.com/dejakob/react-native-modal-walk-through",
7 | "author": "dejakob",
8 | "license": "MIT",
9 | "devDependencies": {
10 | "eslint": "^3.19.0",
11 | "eslint-config-airbnb": "^15.0.1",
12 | "eslint-plugin-import": "^2.3.0",
13 | "eslint-plugin-jsx-a11y": "^5.0.3",
14 | "eslint-plugin-react": "^7.0.1"
15 | },
16 | "scripts": {
17 | "lint": "eslint **/*.js"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------