@nghinv/react-native-app-tour
Version:
React Native app tour Library
422 lines (385 loc) • 16.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _reactFastCompare = _interopRequireDefault(require("react-fast-compare"));
var _reactNativeSvg = require("react-native-svg");
var _reactNativeAnimateableText = _interopRequireDefault(require("react-native-animateable-text"));
var _reactNativeGestureHandler = require("react-native-gesture-handler");
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _AppTourContext = require("./AppTourContext");
var _hook = require("./hook");
var _math = require("./math");
var _MenuButton = _interopRequireDefault(require("./MenuButton"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/**
* Created by nghinv on Wed Jun 23 2021
* Copyright (c) 2021 nghinv@lumi.biz
*/
const RectAnimated = _reactNativeReanimated.default.createAnimatedComponent(_reactNativeSvg.Rect);
const CircleAnimated = _reactNativeReanimated.default.createAnimatedComponent(_reactNativeSvg.Circle);
const IS_IOS = _reactNative.Platform.OS === 'ios';
function MashView(props) {
var _options$triangleHeig, _options$stepHeight, _options$pathAnimated, _options$backgroundCo, _options$borderRadius, _options$backgroundCo2, _options$stepBackgrou, _options$stepTitleCol;
const {
progress,
currentStep,
scene,
onStop
} = props;
const {
nodes,
options
} = (0, _react.useContext)(_AppTourContext.AppTourContext);
const {
emitEvent
} = (0, _hook.useEvent)();
const defaultTarget = (0, _hook.useVectorLayout)();
const dimension = (0, _reactNative.useWindowDimensions)();
const contentHeight = (0, _reactNativeReanimated.useSharedValue)(0);
const contentWidth = (0, _reactNativeReanimated.useSharedValue)(0);
const activeNode = (0, _reactNativeReanimated.useSharedValue)(0);
const TriangleHeight = (_options$triangleHeig = options === null || options === void 0 ? void 0 : options.triangleHeight) !== null && _options$triangleHeig !== void 0 ? _options$triangleHeig : 8;
const StepHeight = (_options$stepHeight = options === null || options === void 0 ? void 0 : options.stepHeight) !== null && _options$stepHeight !== void 0 ? _options$stepHeight : 20;
const pathAnimated = (_options$pathAnimated = options === null || options === void 0 ? void 0 : options.pathAnimated) !== null && _options$pathAnimated !== void 0 ? _options$pathAnimated : IS_IOS;
const onNextStep = () => {
const nextValue = currentStep.value + 1;
const sceneLength = scene.length;
if (nextValue <= sceneLength - 1) {
const currentScene = scene[nextValue];
currentStep.value = nextValue;
emitEvent('AppTourEvent', {
name: 'onNext',
step: nextValue,
node: nodes.value.find(n => n.id === currentScene.id),
scene: currentScene
});
} else {
onStop();
}
};
const onPressNode = () => {
const currentScene = scene[currentStep.value];
const node = nodes.value.find(n => n.id === currentScene.id);
if (currentScene.enablePressNode) {
var _node$onPress;
node === null || node === void 0 ? void 0 : (_node$onPress = node.onPress) === null || _node$onPress === void 0 ? void 0 : _node$onPress.call(node);
}
if (currentScene.pressToNext) {
emitEvent('AppTourEvent', {
name: 'onPressNode',
step: currentStep.value,
node,
scene: currentScene
});
if (currentScene.nextDelay) {
setTimeout(() => {
onNextStep();
}, currentScene.nextDelay);
} else {
onNextStep();
}
}
};
const onGestureEventNode = (0, _reactNativeReanimated.useAnimatedGestureHandler)({
onActive: () => {
(0, _reactNativeReanimated.runOnJS)(onPressNode)();
},
onStart: () => {
const currentScene = scene[currentStep.value];
if (currentScene.enablePressNode) {
activeNode.value = (0, _math.withAnimation)(1);
}
},
onFinish: () => {
const currentScene = scene[currentStep.value];
if (currentScene.enablePressNode) {
activeNode.value = (0, _math.withAnimation)(0);
}
}
});
const onContentLayout = event => {
contentHeight.value = event.nativeEvent.layout.height;
contentWidth.value = event.nativeEvent.layout.width;
};
const animatedPropsBackdrop = (0, _reactNativeReanimated.useAnimatedProps)(() => {
var _options$backdropOpac;
return {
fill: (0, _reactNativeReanimated.interpolateColor)(progress.value, [0, 1], ['rgba(0, 0, 0, 0)', `rgba(0, 0, 0, ${(_options$backdropOpac = options === null || options === void 0 ? void 0 : options.backdropOpacity) !== null && _options$backdropOpac !== void 0 ? _options$backdropOpac : 0.8})`])
};
});
const animatedPropsMaskCircle = (0, _reactNativeReanimated.useAnimatedProps)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target,
maskType
} = node;
return {
cx: (0, _math.withAnimation)(target.x.value + target.width.value / 2, pathAnimated),
cy: (0, _math.withAnimation)(target.y.value + target.height.value / 2, pathAnimated),
r: maskType === 'circle' ? (0, _math.withAnimation)(Math.max(target.width.value, target.height.value) / 2, pathAnimated) : 0
};
});
const animatedPropsMaskRect = (0, _reactNativeReanimated.useAnimatedProps)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target,
maskType
} = node;
return {
x: (0, _math.withAnimation)(target.x.value, pathAnimated),
y: (0, _math.withAnimation)(target.y.value, pathAnimated),
width: maskType !== 'circle' ? (0, _math.withAnimation)(target.width.value, pathAnimated) : 0,
height: maskType !== 'circle' ? (0, _math.withAnimation)(target.height.value, pathAnimated) : 0
};
});
const childrenStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
var _options$colorNodeOnP;
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target
} = node;
return {
width: target.width.value,
height: target.height.value,
borderRadius: target.height.value,
backgroundColor: (0, _reactNativeReanimated.interpolateColor)(activeNode.value, [0, 1], ['transparent', (_options$colorNodeOnP = options === null || options === void 0 ? void 0 : options.colorNodeOnPress) !== null && _options$colorNodeOnP !== void 0 ? _options$colorNodeOnP : 'rgba(255, 255, 255, 0.8)']),
transform: [{
translateX: target.x.value
}, {
translateY: target.y.value
}, {
scale: (0, _reactNativeReanimated.interpolate)(activeNode.value, [0, 1], [1, 1.2])
}]
};
});
const contentStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target
} = node;
const isTargetTopScreen = target.y.value + target.height.value < dimension.height / 2;
const translateY = isTargetTopScreen ? (0, _math.withAnimation)(target.y.value + target.height.value + TriangleHeight) : (0, _math.withAnimation)(target.y.value - contentHeight.value - TriangleHeight);
const isOverScreen = contentWidth.value + target.x.value > dimension.width - 32;
const delta = (dimension.width - contentWidth.value) / 2;
const translateX = isOverScreen ? (0, _math.withAnimation)(Math.max(0, delta)) : (0, _math.withAnimation)(target.x.value);
return {
opacity: (0, _reactNativeReanimated.interpolate)(progress.value, [0, 0.9, 1], [0, 0, 1]),
transform: [{
translateX
}, {
translateY
}, {
scale: (0, _reactNativeReanimated.interpolate)(progress.value, [0, 1], [0.6, 1])
}]
};
});
const triangleStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target,
maskType
} = node;
const isTargetTopScreen = target.y.value + target.height.value < dimension.height / 2;
const isOverScreen = contentWidth.value + target.x.value > dimension.width - 32;
const delta = (dimension.width - contentWidth.value) / 2;
const originTranslateX = isOverScreen ? Math.max(0, delta) : target.x.value;
const translateY = isTargetTopScreen ? -TriangleHeight : contentHeight.value;
const translateX = maskType === 'circle' ? (0, _math.withAnimation)(target.x.value + target.width.value / 2 - originTranslateX - TriangleHeight) : (0, _math.withAnimation)(target.x.value - originTranslateX + 12);
return {
transform: [{
translateY
}, {
translateX
}, {
rotate: isTargetTopScreen ? '0deg' : '180deg'
}]
};
});
const stepStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
target
} = node;
const translateX = target.x.value < 32 ? target.x.value + target.width.value - StepHeight / 2 : target.x.value - StepHeight / 2;
const translateY = target.y.value - StepHeight / 2;
return {
transform: [{
translateX
}, {
translateY
}]
};
});
const animatedPropsStep = (0, _reactNativeReanimated.useAnimatedProps)(() => {
return {
text: `${currentStep.value + 1}`
};
});
const animatedPropsTitle = (0, _reactNativeReanimated.useAnimatedProps)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
title
} = node;
return {
text: title
};
});
const animatedPropsDescribe = (0, _reactNativeReanimated.useAnimatedProps)(() => {
const {
node
} = (0, _math.getCurrentNode)(nodes, scene, currentStep, defaultTarget);
const {
describe
} = node;
return {
text: describe
};
});
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
pointerEvents: "box-none",
style: styles.container
}, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.Svg, {
height: "100%",
width: "100%"
}, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.Defs, null, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.Mask, {
id: "mask",
x: "0",
y: "0",
height: "100%",
width: "100%"
}, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.Rect, {
height: "100%",
width: "100%",
fill: "#fff"
}), /*#__PURE__*/_react.default.createElement(CircleAnimated, {
animatedProps: animatedPropsMaskCircle,
fill: "black"
}), /*#__PURE__*/_react.default.createElement(RectAnimated, {
animatedProps: animatedPropsMaskRect,
fill: "black"
}))), /*#__PURE__*/_react.default.createElement(RectAnimated, {
animatedProps: animatedPropsBackdrop,
height: "100%",
width: "100%",
mask: "url(#mask)",
"fill-opacity": "0"
})), /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
style: [styles.content, {
backgroundColor: (_options$backgroundCo = options === null || options === void 0 ? void 0 : options.backgroundColor) !== null && _options$backgroundCo !== void 0 ? _options$backgroundCo : 'white',
borderRadius: (_options$borderRadius = options === null || options === void 0 ? void 0 : options.borderRadius) !== null && _options$borderRadius !== void 0 ? _options$borderRadius : 5
}, contentStyle],
onLayout: onContentLayout
}, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
style: [styles.triangle, {
borderBottomColor: (_options$backgroundCo2 = options === null || options === void 0 ? void 0 : options.backgroundColor) !== null && _options$backgroundCo2 !== void 0 ? _options$backgroundCo2 : 'white',
borderLeftWidth: TriangleHeight,
borderRightWidth: TriangleHeight,
borderBottomWidth: TriangleHeight
}, triangleStyle]
}), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: styles.viewTitle
}, (options === null || options === void 0 ? void 0 : options.titleShow) !== false && /*#__PURE__*/_react.default.createElement(_reactNativeAnimateableText.default, {
style: [styles.txtTitle, options === null || options === void 0 ? void 0 : options.titleStyle],
animatedProps: animatedPropsTitle
}), /*#__PURE__*/_react.default.createElement(_reactNativeAnimateableText.default, {
style: [styles.txtDescribe, options === null || options === void 0 ? void 0 : options.describeStyle],
animatedProps: animatedPropsDescribe
})), /*#__PURE__*/_react.default.createElement(_MenuButton.default, {
currentStep: currentStep,
onStop: onStop
})), (options === null || options === void 0 ? void 0 : options.stepShow) !== false && /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
style: [styles.stepView, {
backgroundColor: (_options$stepBackgrou = options === null || options === void 0 ? void 0 : options.stepBackgroundColor) !== null && _options$stepBackgrou !== void 0 ? _options$stepBackgrou : 'green',
height: StepHeight,
minWidth: StepHeight,
borderRadius: StepHeight / 2
}, stepStyle]
}, /*#__PURE__*/_react.default.createElement(_reactNativeAnimateableText.default, {
style: [styles.txtStep, {
color: (_options$stepTitleCol = options === null || options === void 0 ? void 0 : options.stepTitleColor) !== null && _options$stepTitleCol !== void 0 ? _options$stepTitleCol : 'white'
}],
animatedProps: animatedPropsStep
})), /*#__PURE__*/_react.default.createElement(_reactNativeGestureHandler.TapGestureHandler, {
onGestureEvent: onGestureEventNode,
enabled: !(options !== null && options !== void 0 && options.nativeModal)
}, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
style: [styles.children, childrenStyle]
}, (options === null || options === void 0 ? void 0 : options.nativeModal) && /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
onPress: onPressNode,
style: styles.childrenButton
}))));
}
const styles = _reactNative.StyleSheet.create({
container: { ..._reactNative.StyleSheet.absoluteFillObject
},
children: {
position: 'absolute',
overflow: 'hidden'
},
stepView: {
position: 'absolute',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: 'white',
paddingHorizontal: 4
},
triangle: {
position: 'absolute',
width: 0,
height: 0,
zIndex: 0,
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
borderStyle: 'solid'
},
content: {
position: 'absolute',
minWidth: 180
},
viewTitle: {
paddingHorizontal: 16,
paddingTop: 12,
paddingBottom: 4,
zIndex: 1
},
txtTitle: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 2
},
txtDescribe: {
fontSize: 16
},
txtStep: {
fontSize: 10,
lineHeight: 12,
fontWeight: '500'
},
childrenButton: {
flex: 1
}
});
var _default = /*#__PURE__*/_react.default.memo(MashView, _reactFastCompare.default);
exports.default = _default;
//# sourceMappingURL=MashView.js.map