diff --git a/README.md b/README.md
index 604189a9..0e5c58e1 100644
--- a/README.md
+++ b/README.md
@@ -174,6 +174,28 @@ class HomeScreen {
}
}
```
+### Add onPress handler for masked component
+If you want the user to be able to interact with app while stepping through the tutorial, You can add onPress event to to one of Step components.
+
+```js
+import { walkthroughable, CopilotStep } from '@okgrow/react-native-copilot';
+
+const CopilotTouchableOpacity = walkthroughable(TouchableOpacity);
+
+class HomeScreen {
+ render() {
+ return (
+
+
+ Hello world!
+
+
+ );
+ }
+}
+```
### Triggering the tutorial
Use `this.props.start()` in the root component in order to trigger the tutorial. You can either invoke it with a touch event or in `componentDidMount`. Note that the component and all its descendants must be mounted before starting the tutorial since the `CopilotStep`s need to be registered first.
diff --git a/src/components/CopilotModal.js b/src/components/CopilotModal.js
index a47e66b8..f7e50ab0 100644
--- a/src/components/CopilotModal.js
+++ b/src/components/CopilotModal.js
@@ -1,6 +1,15 @@
// @flow
import React, { Component } from 'react';
-import { Animated, Easing, View, NativeModules, Modal, StatusBar, Platform } from 'react-native';
+import {
+ Animated,
+ Easing,
+ View,
+ NativeModules,
+ Modal,
+ StatusBar,
+ Platform,
+ I18nManager,
+} from 'react-native';
import Tooltip from './Tooltip';
import StepNumber from './StepNumber';
import styles, { MARGIN, ARROW_SIZE, STEP_NUMBER_DIAMETER, STEP_NUMBER_RADIUS } from './style';
@@ -36,6 +45,10 @@ type State = {
const noop = () => {};
+const rtl = I18nManager.isRTL;
+const start = rtl ? 'right' : 'left';
+const end = rtl ? 'left' : 'right';
+
class CopilotModal extends Component {
static defaultProps = {
easing: Easing.elastic(0.7),
@@ -101,15 +114,31 @@ class CopilotModal extends Component {
obj.top -= StatusBar.currentHeight; // eslint-disable-line no-param-reassign
}
- let stepNumberLeft = obj.left - STEP_NUMBER_RADIUS;
+ let stepNumberLeft;
+
+ const edgeCase = (stepLeft) => {
+ if (stepLeft > layout.width - STEP_NUMBER_DIAMETER) {
+ return layout.width - STEP_NUMBER_DIAMETER;
+ }
+ return stepLeft;
+ };
+
+ if (!rtl) {
+ stepNumberLeft = obj.left - STEP_NUMBER_RADIUS;
- if (stepNumberLeft < 0) {
+ if (stepNumberLeft < 0) {
+ stepNumberLeft = (obj.left + obj.width) - STEP_NUMBER_RADIUS;
+ stepNumberLeft = edgeCase(stepNumberLeft);
+ }
+ } else {
stepNumberLeft = (obj.left + obj.width) - STEP_NUMBER_RADIUS;
- if (stepNumberLeft > layout.width - STEP_NUMBER_DIAMETER) {
- stepNumberLeft = layout.width - STEP_NUMBER_DIAMETER;
+ if (stepNumberLeft > layout.width) {
+ stepNumberLeft = obj.left - STEP_NUMBER_RADIUS;
+ stepNumberLeft = edgeCase(stepNumberLeft);
}
}
+
const center = {
x: obj.left + (obj.width / 2),
y: obj.top + (obj.height / 2),
@@ -137,15 +166,15 @@ class CopilotModal extends Component {
}
if (horizontalPosition === 'left') {
- tooltip.right = Math.max(layout.width - (obj.left + obj.width), 0);
+ tooltip[end] = Math.max(layout.width - (obj.left + obj.width), 0);
tooltip.right = tooltip.right === 0 ? tooltip.right + MARGIN : tooltip.right;
tooltip.maxWidth = layout.width - tooltip.right - MARGIN;
- arrow.right = tooltip.right + MARGIN;
+ arrow[end] = tooltip[end] + MARGIN;
} else {
- tooltip.left = Math.max(obj.left, 0);
+ tooltip[start] = Math.max(obj.left, 0);
tooltip.left = tooltip.left === 0 ? tooltip.left + MARGIN : tooltip.left;
tooltip.maxWidth = layout.width - tooltip.left - MARGIN;
- arrow.left = tooltip.left + MARGIN;
+ arrow[start] = tooltip[start] + MARGIN;
}
const animate = {
@@ -249,7 +278,7 @@ class CopilotModal extends Component {
style={[
styles.stepNumberContainer,
{
- left: this.state.animatedValues.stepNumberLeft,
+ [start]: this.state.animatedValues.stepNumberLeft,
top: Animated.add(this.state.animatedValues.top, -STEP_NUMBER_RADIUS),
},
]}
diff --git a/src/components/ViewMask.js b/src/components/ViewMask.js
index de4884b9..315386bf 100644
--- a/src/components/ViewMask.js
+++ b/src/components/ViewMask.js
@@ -1,10 +1,15 @@
// @flow
import React, { Component } from 'react';
-
-import { View, Animated } from 'react-native';
+import PropTypes from 'prop-types';
+import { View, Animated, I18nManager, TouchableOpacity } from 'react-native';
import styles from './style';
-import type { valueXY } from '../types';
+import type { CopilotContext, valueXY } from '../types';
+
+
+const rtl = I18nManager.isRTL;
+const start = rtl ? 'right' : 'left';
+const end = rtl ? 'left' : 'right';
type Props = {
size: valueXY,
@@ -26,6 +31,10 @@ type State = {
};
class ViewMask extends Component {
+ static contextTypes = {
+ _copilot: PropTypes.object,
+ }
+
state = {
size: new Animated.ValueXY({ x: 0, y: 0 }),
position: new Animated.ValueXY({ x: 0, y: 0 }),
@@ -37,6 +46,10 @@ class ViewMask extends Component {
}
}
+ context: {
+ _copilot: CopilotContext,
+ }
+
animate = (size: valueXY = this.props.size, position: valueXY = this.props.position): void => {
if (this.state.animated) {
Animated.parallel([
@@ -78,14 +91,14 @@ class ViewMask extends Component {
style={[
styles.overlayRectangle,
{
- right: leftOverlayRight,
+ [end]: leftOverlayRight,
}]}
/>
{
styles.overlayRectangle,
{
top: bottomOverlayTopBoundary,
- left: verticalOverlayLeftBoundary,
- right: verticalOverlayRightBoundary,
+ [start]: verticalOverlayLeftBoundary,
+ [end]: verticalOverlayRightBoundary,
},
]}
/>
@@ -103,11 +116,22 @@ class ViewMask extends Component {
styles.overlayRectangle,
{
bottom: topOverlayBottomBoundary,
- left: verticalOverlayLeftBoundary,
- right: verticalOverlayRightBoundary,
+ [start]: verticalOverlayLeftBoundary,
+ [end]: verticalOverlayRightBoundary,
},
]}
/>
+
);
}