├── .flowconfig
├── .gitignore
├── README.md
├── demo
├── android.gif
├── demo.js
└── ios.gif
├── index.d.ts
├── index.js
├── package.json
└── src
├── IntroComponent.js
├── IntroManage.js
├── IntroModal.js
├── constants.js
└── index.js
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*.web.js
5 | .*/*.android.js
6 |
7 | # Some modules have their own node_modules with overlap
8 | .*/node_modules/node-haste/.*
9 |
10 | # Ugh
11 | .*/node_modules/babel.*
12 | .*/node_modules/babylon.*
13 | .*/node_modules/invariant.*
14 |
15 | # Ignore react and fbjs where there are overlaps, but don't ignore
16 | # anything that react-native relies on
17 | .*/node_modules/fbjs/lib/Map.js
18 | .*/node_modules/fbjs/lib/Promise.js
19 | .*/node_modules/fbjs/lib/fetch.js
20 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js
21 | .*/node_modules/fbjs/lib/isEmpty.js
22 | .*/node_modules/fbjs/lib/crc32.js
23 | .*/node_modules/fbjs/lib/ErrorUtils.js
24 |
25 | # Flow has a built-in definition for the 'react' module which we prefer to use
26 | # over the currently-untyped source
27 | .*/node_modules/react/react.js
28 | .*/node_modules/react/lib/React.js
29 | .*/node_modules/react/lib/ReactDOM.js
30 |
31 | # Ignore commoner tests
32 | .*/node_modules/commoner/test/.*
33 |
34 | # See https://github.com/facebook/flow/issues/442
35 | .*/react-tools/node_modules/commoner/lib/reader.js
36 |
37 | # Ignore jest
38 | .*/node_modules/jest-cli/.*
39 |
40 | # Ignore Website
41 | .*/website/.*
42 |
43 | [include]
44 |
45 | [libs]
46 | node_modules/react-native/Libraries/react-native/react-native-interface.js
47 |
48 | [options]
49 | module.system=haste
50 |
51 | munge_underscores=true
52 |
53 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
54 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub'
55 |
56 | suppress_type=$FlowIssue
57 | suppress_type=$FlowFixMe
58 | suppress_type=$FixMe
59 |
60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
61 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
62 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
63 |
64 | [version]
65 | 0.21.0
66 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IJ
26 | #
27 | .idea
28 | .gradle
29 | local.properties
30 |
31 | # node.js
32 | #
33 | node_modules/
34 | npm-debug.log
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-intro
2 | A way for new feature introduction and step-by-step users guide for your react-native app
3 |
4 | # Install
5 | Run ```npm install react-native-intro --save``` in your Project dir
6 |
7 | # Usage
8 |
9 | 1. react-native-intro exports two APIs, default is ```Intro``` component, and the other one is ```intro``` function. see [demo](./demo/) get more informations.
10 |
11 | 2. Use ```Intro``` component wrap your components and pass some props to Intro. Maybe you need set the style props too;
12 |
13 | ```
14 | import Intro, {IntroManage} from 'react-native-intro';
15 |
16 |
19 |
20 |
21 | .....
22 |
23 | componentDidMount() {
24 |
25 | // and start
26 | var myIntro = new IntroManage();
27 | myIntro.start();
28 |
29 | }
30 |
31 | ```
32 |
33 | #Props
34 | ###content: string | ReactElement
35 |
36 | ###step: the step sort
37 |
38 | # Warning
39 | *This Component does not support your component Wrapped by `Redux connect` currently;*
40 |
41 | # screen shorts
42 |
43 | 
44 | 
45 |
--------------------------------------------------------------------------------
/demo/android.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuzheng644607/react-native-intro/a1d5a4e2865ee3390e19495682324433d010b7c7/demo/android.gif
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: liuyany.liu
3 | * @Date: 2017-02-27 19:21:32
4 | * @Last modified by: lyan
5 | * @Last modified time: 2017-03-02 20:54:00
6 | */
7 |
8 | import {
9 | StyleSheet,
10 | View,
11 | TextInput,
12 | Image,
13 | Text,
14 | TouchableOpacity
15 | } from 'react-native';
16 |
17 | import React, {
18 | Component
19 | } from 'react';
20 |
21 | import Intro, { intro } from 'react-native-intro';
22 |
23 | export default class Example extends Component {
24 | state = {
25 | value: 'hahah'
26 | }
27 | render() {
28 | return (
29 |
30 |
35 | this.setState({value: v})}
38 | value={this.state.value}/>
39 |
43 |
45 |
46 | }
47 | step={2}>
48 | 呵呵呵呵
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
65 | 点我
66 |
67 |
68 |
69 | );
70 | }
71 |
72 | componentDidMount() {
73 | this.intro = intro({group: 'test1'});
74 | }
75 |
76 | _showModal() {
77 | this.intro.start();
78 | }
79 | }
80 |
81 | const styles = StyleSheet.create({
82 | container: {
83 | position: 'absolute',
84 | left: 0,
85 | top: 0,
86 | right: 0,
87 | bottom:0,
88 | },
89 | content: {
90 | width: 200,
91 | height: 300,
92 | position: 'absolute',
93 | top: 100,
94 | left: 100,
95 | borderWidth: 1,
96 | borderColor: 'red'
97 | },
98 | button: {
99 | width: 100,
100 | height: 44,
101 | position: 'absolute',
102 | bottom: 100
103 | },
104 | });
105 |
--------------------------------------------------------------------------------
/demo/ios.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuzheng644607/react-native-intro/a1d5a4e2865ee3390e19495682324433d010b7c7/demo/ios.gif
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleProp, ViewStyle } from 'react-native';
3 | import { ComponentClass, Component } from 'react';
4 |
5 | interface IIntroComponentProps {
6 | /**
7 | * 分组
8 | */
9 | group?: string;
10 |
11 | /**
12 | * 第几步
13 | */
14 | step: number;
15 |
16 | /**
17 | * 展示内容
18 | */
19 | content?: JSX.Element;
20 |
21 | /**
22 | * 样式
23 | */
24 | style?: StyleProp;
25 | }
26 |
27 | export declare class Intro extends Component {}
28 |
29 | export interface IntroManageOptions {
30 | /**
31 | * 当前分组
32 | */
33 | group?: string;
34 |
35 | /**
36 | * 循环
37 | */
38 | loop?: boolean;
39 |
40 | /**
41 | * 初始step 索引
42 | */
43 | startIndex?: number;
44 |
45 | /**
46 | * 是否显示步骤数, 默认true
47 | */
48 | showStepNumber?: boolean;
49 |
50 | /**
51 | * 蒙层的样式,可以定义透明度,背景颜色等
52 | */
53 | maskStyle?: StyleProp;
54 |
55 | /**
56 | * 高亮的内容区域是否可交互,用于防止用户点击在高亮内容上面
57 | */
58 | touchable?: boolean;
59 |
60 | /**
61 | * 点击蒙层是否关闭
62 | */
63 | maskClosable?: boolean;
64 |
65 | /**
66 | * 自定义渲染提示内容
67 | */
68 | contentRender?: (content: JSX.Element, step: number) => JSX.Element;
69 | }
70 |
71 | export declare class IntroManage {
72 | constructor(opts: IntroManageOptions);
73 | /**
74 | * 开始
75 | */
76 | start(): void;
77 |
78 | /**
79 | * 结束
80 | */
81 | stop(): void;
82 |
83 | /**
84 | * next step
85 | */
86 | next(): void;
87 |
88 | /**
89 | * previous step
90 | */
91 | prev(): void;
92 |
93 | /**
94 | * go to step direct (index)
95 | * @param index
96 | */
97 | private toStep(index: number): void;
98 | }
99 |
100 | export default Intro;
101 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: liuyany.liu
3 | * @Date: 2016-12-20 14:27:41
4 | * @Last modified by: lyan
5 | * @Last modified time: 2017-02-27 21:54:23
6 | */
7 |
8 | import {IntroManage} from './src/IntroManage';
9 | import {Intro} from './src/IntroComponent';
10 |
11 | export default Intro;
12 | export { IntroManage }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-intro",
3 | "version": "0.0.2",
4 | "description": "A way for new feature introduction and step-by-step users guide for your react-native app",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+ssh://git@github.com/liuzheng644607/react-native-intro.git"
12 | },
13 | "keywords": [
14 | "react-native-intro",
15 | "intro",
16 | "react-native"
17 | ],
18 | "author": "lyan",
19 | "license": "ISC",
20 | "bugs": {
21 | "url": "https://github.com/liuzheng644607/react-native-intro/issues"
22 | },
23 | "dependencies": {
24 | "react-native-root-siblings": "^1.1.2"
25 | },
26 | "homepage": "https://github.com/liuzheng644607/react-native-intro#readme"
27 | }
28 |
--------------------------------------------------------------------------------
/src/IntroComponent.js:
--------------------------------------------------------------------------------
1 | import {
2 | StyleSheet,
3 | TouchableOpacity,
4 | View,
5 | Text,
6 | Dimensions,
7 | Animated
8 | } from "react-native";
9 |
10 | import React, { Component } from "react";
11 | import {groupMap, DEFAULT_GROUP} from './constants';
12 |
13 | export class Intro extends Component {
14 | setNativeProps(obj) {
15 | this._refIntro.setNativeProps(obj);
16 | }
17 |
18 | componentDidMount() {
19 | const { group, step, content, disable } = this.props;
20 |
21 | if (!groupMap[group || DEFAULT_GROUP]) {
22 | groupMap[group || DEFAULT_GROUP] = {};
23 | }
24 |
25 | let groupA = groupMap[group || DEFAULT_GROUP];
26 |
27 | if (!groupA[step]) {
28 | groupA[step] = {
29 | content,
30 | disable,
31 | target: this,
32 | refTarget: this._refIntro,
33 | _index: 0
34 | };
35 | } else {
36 | ++groupA[step]._index;
37 | }
38 | }
39 |
40 | measure() {
41 | this._refIntro.measure.apply(this._refIntro, arguments);
42 | }
43 |
44 | componentWillUnmount() {
45 | const { group, step, content, disable } = this.props;
46 | var groupA = groupMap[group || DEFAULT_GROUP][step];
47 |
48 | if (groupA._index > 0) {
49 | --groupA._index;
50 | } else {
51 | delete groupMap[group || DEFAULT_GROUP][step];
52 | if (Object.keys(groupMap[group || DEFAULT_GROUP]).length === 0) {
53 | delete groupMap[group && DEFAULT_GROUP];
54 | }
55 | }
56 | }
57 |
58 | render() {
59 | this.html = (
60 | (this._refIntro = c)}
63 | >
64 | {this.props.children}
65 |
66 | );
67 |
68 | return this.html;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/IntroManage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: liuyany.liu
3 | * @Date: 2017-02-07 15:45:15
4 | * @Last modified by: lyan
5 | * @Last modified time: 2017-03-02 20:54:24
6 | */
7 |
8 | import {
9 | StyleSheet,
10 | TouchableOpacity,
11 | View,
12 | Text,
13 | Dimensions,
14 | Animated
15 | } from "react-native";
16 | import React, { cloneElement, Component } from "react";
17 | import RootSiblings from "react-native-root-siblings";
18 | import {IntroModal} from './IntroModal';
19 | import {groupMap, DEFAULT_GROUP, DEFAULTOPTIONS} from './constants';
20 |
21 | const offsetW = 4;
22 |
23 | export class IntroManage {
24 | constructor(opts = {}) {
25 | opts = this.opts = Object.assign({}, DEFAULTOPTIONS, opts);
26 | this.groupName = opts.group;
27 | this.introData = groupMap[this.groupName];
28 | if (!this.introData) {
29 | return;
30 | }
31 |
32 | this.loop = opts.loop;
33 |
34 | this.stepArr = Object.keys(this.introData).sort();
35 | this.stepLength = this.stepArr.length;
36 | this.index = opts.startIndex || 0;
37 | this.timer = null;
38 | this.stepTimer = null;
39 |
40 | this.refModal = null;
41 | this.sibling = null;
42 | }
43 |
44 | start = () => {
45 | if (!this.sibling) {
46 | this.sibling = new RootSiblings(
47 | (
48 | (this.refModal = c)}
50 | next={this.next}
51 | prev={this.prev}
52 | stop={this.stop}
53 | contentRender={this.opts.contentRender}
54 | showStepNumber={this.opts.showStepNumber}
55 | maskStyle={this.opts.maskStyle}
56 | touchable={this.opts.touchable}
57 | maskClosable={this.opts.maskClosable}
58 | />
59 | )
60 | );
61 | }
62 | this.cleartTimers();
63 | stepTimer = setTimeout(() => {
64 | this.toStep(this.index);
65 | });
66 | }
67 |
68 | stop = () => {
69 | this.cleartTimers();
70 | if (this.sibling) {
71 | this.sibling.destroy();
72 | this.sibling = null;
73 | }
74 | this.index = 0;
75 | }
76 |
77 | prev = () => {
78 | if (this.index <= 0) {
79 | if (this.loop) {
80 | this.index = this.stepLength;
81 | } else {
82 | return;
83 | }
84 | }
85 |
86 | this.index--;
87 | this.toStep(this.index);
88 | }
89 |
90 | next = () => {
91 | if (this.index >= this.stepLength - 1) {
92 | if (this.loop) {
93 | this.index = -1;
94 | } else {
95 | return;
96 | }
97 | }
98 |
99 | this.index++;
100 | this.toStep(this.index);
101 | }
102 |
103 | toStep = (index) => {
104 | this.index = index;
105 | const currentStep = this.introData[this.stepArr[index]];
106 | const content = currentStep.content;
107 |
108 | const target = currentStep.target;
109 | const refTarget = currentStep.refTarget;
110 |
111 | let element = target.html;
112 | element = cloneElement(element, {
113 | style: [element.props.style]
114 | });
115 |
116 | const refModal = this.refModal;
117 |
118 | this.refModal.innerElement = null;
119 | this.refModal.forceUpdate();
120 |
121 | new Promise((resolve, reject) => {
122 | refTarget.measure((x, y, width, height, pageX, pageY) => {
123 | resolve({ x, y, width, height, pageX, pageY });
124 | }, () => reject);
125 | }).then(res => {
126 | let obj = {
127 | width: res.width,
128 | height: res.height,
129 | left: res.pageX,
130 | top: res.pageY
131 | };
132 | // hide the tooltip
133 | refModal.toggleTooltip(false);
134 |
135 | timer = setTimeout(() => {
136 | refModal.innerElement = element;
137 | refModal.currentStep = index + 1;
138 | refModal.content =
139 | typeof content === "string" ? (
140 |
141 | {content}
142 |
143 | ) : (
144 | content
145 | );
146 | refModal.forceUpdate(() => {
147 | refModal.refContainer.setNativeProps({
148 | style: obj
149 | });
150 | });
151 | refModal.toggleTooltip(true);
152 | }, 300);
153 |
154 | refModal.animateMove({
155 | width: res.width + offsetW,
156 | height: res.height + offsetW,
157 | left: res.pageX - offsetW / 2,
158 | top: res.pageY - offsetW / 2
159 | });
160 | });
161 | }
162 |
163 | cleartTimers = () => {
164 | clearTimeout(this.stepTimer);
165 | clearTimeout(this.timer);
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/IntroModal.js:
--------------------------------------------------------------------------------
1 | import {
2 | StyleSheet,
3 | TouchableOpacity,
4 | View,
5 | Text,
6 | Dimensions,
7 | Animated,
8 | } from 'react-native';
9 |
10 | import React, { Component } from 'react';
11 |
12 | const { width, height } = Dimensions.get('window');
13 | const [CLIENT_WIDTH, CLIENT_HEIGHT] = [width, height];
14 | let zIndex = 999;
15 |
16 | export class IntroModal extends Component {
17 | static defaultProps = {
18 | showStepNumber: true,
19 | touchable: false,
20 | maskClosable: true,
21 | };
22 | constructor(props) {
23 | super(props);
24 |
25 | this.innerElement = null;
26 | this.currentStep = 1;
27 |
28 | this._aniWidth = new Animated.Value(0);
29 | this._aniHeight = new Animated.Value(0);
30 | this._aniLeft = new Animated.Value(0);
31 | this._aniTop = new Animated.Value(0);
32 |
33 | this._aniOpacity = new Animated.Value(0);
34 |
35 | this._aniStepNumLeft = new Animated.Value(0);
36 | }
37 |
38 | animateMove(obj = {}) {
39 | var duration = 300;
40 |
41 | var stepNumLeft = obj.left - 12;
42 |
43 | if (stepNumLeft < 0) {
44 | stepNumLeft = obj.left + obj.width - 12;
45 | if (stepNumLeft > CLIENT_WIDTH - 24) {
46 | stepNumLeft = CLIENT_WIDTH - 24;
47 | }
48 | }
49 |
50 | Animated.parallel([
51 | Animated.timing(this._aniWidth, {
52 | duration,
53 | toValue: obj.width,
54 | }),
55 |
56 | Animated.timing(this._aniHeight, {
57 | duration,
58 | toValue: obj.height,
59 | }),
60 |
61 | Animated.timing(this._aniLeft, {
62 | duration,
63 | toValue: obj.left,
64 | }),
65 |
66 | Animated.timing(this._aniTop, {
67 | duration,
68 | toValue: obj.top,
69 | }),
70 |
71 | Animated.timing(this._aniStepNumLeft, {
72 | duration,
73 | toValue: stepNumLeft,
74 | }),
75 | ]).start();
76 |
77 | var centerPoint = {
78 | x: obj.left + obj.width / 2,
79 | y: obj.top + obj.height / 2,
80 | };
81 |
82 | var relative2Left = centerPoint.x;
83 | var relative2Top = centerPoint.y;
84 | var relative2Bottom = Math.abs(centerPoint.y - CLIENT_HEIGHT);
85 | var relative2Right = Math.abs(centerPoint.x - CLIENT_WIDTH);
86 |
87 | var whereVerticalPlace = relative2Bottom > relative2Top ? 'bottom' : 'top';
88 | var whereHorizontalPlace =
89 | relative2Left > relative2Right ? 'left' : 'right';
90 |
91 | var margin = 13;
92 | var tooltip = {};
93 | var arrow = {};
94 |
95 | switch (whereVerticalPlace) {
96 | case 'bottom':
97 | tooltip.top = obj.top + obj.height + margin;
98 | arrow.borderBottomColor = '#fff';
99 | arrow.top = tooltip.top - margin + 3;
100 | break;
101 |
102 | case 'top':
103 | tooltip.bottom = CLIENT_HEIGHT - obj.top + margin;
104 | arrow.borderTopColor = '#fff';
105 | arrow.bottom = tooltip.bottom - margin + 3;
106 | break;
107 | default:
108 | // nothing todo
109 | }
110 |
111 | switch (whereHorizontalPlace) {
112 | case 'left':
113 | tooltip.right = Math.max(CLIENT_WIDTH - (obj.left + obj.width), 0);
114 | tooltip.right =
115 | tooltip.right === 0 ? tooltip.right + margin : tooltip.right;
116 | tooltip.maxWidth = CLIENT_WIDTH - tooltip.right - margin;
117 | arrow.right = tooltip.right + margin;
118 | break;
119 |
120 | case 'right':
121 | tooltip.left = Math.max(obj.left, 0);
122 | tooltip.left =
123 | tooltip.left === 0 ? tooltip.left + margin : tooltip.left;
124 | tooltip.maxWidth = CLIENT_WIDTH - tooltip.left - margin;
125 | arrow.left = tooltip.left + margin;
126 | break;
127 | default:
128 | // nothing todo
129 | }
130 |
131 | this.tooltip = tooltip;
132 | this.arrow = arrow;
133 | }
134 |
135 | toggleTooltip(isShow = true) {
136 | Animated.timing(this._aniOpacity, {
137 | toValue: isShow ? 1 : 0,
138 | duration: 200,
139 | }).start();
140 | }
141 |
142 | render() {
143 | const { contentRender, showStepNumber, touchable, maskStyle, maskClosable } = this.props;
144 | return (
145 |
146 |
151 | (this.refHilightBox = c)}
153 | style={[
154 | styles.hilightBox,
155 | { position: 'absolute' },
156 | {
157 | width: this._aniWidth,
158 | height: this._aniHeight,
159 | left: this._aniLeft,
160 | top: this._aniTop,
161 | },
162 | ]}
163 | />
164 | (this.refContainer = c)}
166 | style={[styles.modalContent]}
167 | >
168 | {this.innerElement}
169 | {/* mask the element */}
170 | {touchable ? null : }
171 |
172 | {
173 | showStepNumber ? (
174 |
184 | {this.currentStep}
185 |
186 | ): null
187 | }
188 |
191 | {contentRender ? (
192 |
199 | {contentRender(this.content, this.currentStep)}
200 |
201 | ) : (
202 |
209 | {this.content || null}
210 |
211 | this.props.stop()}
220 | >
221 |
229 | OK
230 |
231 |
232 | this.props.prev()}
235 | >
236 | prev
237 |
238 | this.props.next()}
241 | >
242 | next
243 |
244 |
245 |
246 | )}
247 |
248 | );
249 | }
250 | }
251 |
252 | const styles = StyleSheet.create({
253 | container: {
254 | position: 'absolute',
255 | left: 0,
256 | top: 0,
257 | right: 0,
258 | bottom: 0,
259 | },
260 |
261 | hilightBox: {
262 | position: 'absolute',
263 | backgroundColor: 'rgba(255,255,255,1)',
264 | borderRadius: 2,
265 | },
266 |
267 | arrow: {
268 | position: 'absolute',
269 | borderColor: 'transparent',
270 | borderWidth: 5,
271 | },
272 |
273 | up: {
274 | borderBottomColor: '#fff',
275 | },
276 |
277 | down: {
278 | borderTopColor: '#fff',
279 | },
280 |
281 | toolTip: {
282 | position: 'absolute',
283 | padding: 5,
284 | backgroundColor: '#fff',
285 | borderRadius: 3,
286 | overflow: 'hidden',
287 | },
288 |
289 | stepNum: {
290 | position: 'absolute',
291 | width: 24,
292 | height: 24,
293 | borderWidth: 2,
294 | borderRadius: 12,
295 | borderColor: '#fff',
296 | backgroundColor: '#28a3ef',
297 | overflow: 'hidden',
298 | alignItems: 'center',
299 | justifyContent: 'center',
300 | },
301 |
302 | stepNumText: {
303 | backgroundColor: 'rgba(255,255,255,0)',
304 | fontWeight: 'bold',
305 | color: '#fff',
306 | },
307 |
308 | sibling: {
309 | position: 'absolute',
310 | left: 0,
311 | top: 0,
312 | right: 0,
313 | bottom: 0,
314 | backgroundColor: 'rgba(0,0,0,0.8)',
315 | },
316 |
317 | introButton: {
318 | padding: 2,
319 | borderColor: '#28a3ef',
320 | borderWidth: 1,
321 | borderRadius: 2,
322 | },
323 |
324 | buttonText: {
325 | fontSize: 12,
326 | textAlign: 'center',
327 | color: '#28a3ef',
328 | },
329 |
330 | introBar: {
331 | marginTop: 10,
332 | flexDirection: 'row',
333 | justifyContent: 'flex-end',
334 | },
335 |
336 | modalContent: {
337 | position: 'absolute',
338 | overflow: 'hidden',
339 | },
340 |
341 | modal: {
342 | backgroundColor: 'rgba(0,0,0,0.5)',
343 | },
344 | });
345 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | groupMap = {
4 | groupA: {
5 | 1: {
6 | content: React.Element,
7 | disable: boolean,
8 | target: IntroComponent,
9 | refTarget: ref,
10 | _index: number,
11 | }
12 | }
13 | }
14 | */
15 | export const groupMap = {};
16 |
17 | export const DEFAULT_GROUP = "DEFAULT_GROUP";
18 |
19 | export const DEFAULTOPTIONS = {
20 | group: DEFAULT_GROUP
21 | };
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export {IntroManage} from './IntroManage';
2 | import {Intro} from './IntroComponent';
3 |
4 | export default Intro;
--------------------------------------------------------------------------------