react-native-onboarding-flow
Version:
Beautiful, customizable onboarding flows for React Native with smooth animations
175 lines (170 loc) • 6.64 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const react_native_1 = require("react-native");
const vector_icons_1 = require("@expo/vector-icons");
const OnboardingSlide_1 = __importDefault(require("./OnboardingSlide"));
const { width } = react_native_1.Dimensions.get('window');
const OnboardingModal = ({ visible, slides, currentSlide, onNext, onClose, closeable, showProgress, theme, showPaywall = false, paywallComponent, }) => {
const isValidSlide = currentSlide >= 0 && currentSlide < slides.length;
const isLastSlide = isValidSlide && currentSlide === slides.length - 1;
const currentSlideData = isValidSlide ? slides[currentSlide] : null;
const renderProgressDots = () => {
if (!showProgress)
return null;
return (<react_native_1.View style={styles.progressContainer}>
{slides.map((_, index) => (<react_native_1.View key={index} style={[
styles.progressDot,
{
backgroundColor: index <= currentSlide
? ((theme === null || theme === void 0 ? void 0 : theme.progressDotActiveColor) || '#6B8E5A')
: ((theme === null || theme === void 0 ? void 0 : theme.progressDotColor) || '#E5E5E5'),
width: index === currentSlide ? 24 : 8,
},
]}/>))}
</react_native_1.View>);
};
return (<react_native_1.Modal visible={visible} animationType="slide" presentationStyle="pageSheet" onRequestClose={closeable ? onClose : undefined}>
<react_native_1.SafeAreaView style={[styles.container, { backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.backgroundColor) || 'white' }]}>
{showPaywall && paywallComponent ? (
// Render paywall component in full screen
<react_native_1.View style={styles.paywallContainer}>
{paywallComponent}
</react_native_1.View>) : (<>
{/* Header with optional close button */}
<react_native_1.View style={styles.header}>
<react_native_1.View style={styles.headerSpacer}/>
{closeable && onClose && (<react_native_1.TouchableOpacity onPress={onClose} style={styles.closeButton}>
<vector_icons_1.Ionicons name="close" size={24} color={(theme === null || theme === void 0 ? void 0 : theme.closeButtonColor) || '#666'}/>
</react_native_1.TouchableOpacity>)}
</react_native_1.View>
{/* Progress dots */}
{renderProgressDots()}
{/* Slide content */}
<react_native_1.View style={styles.slideContainer}>
{currentSlideData && currentSlideData.media && (<OnboardingSlide_1.default slide={currentSlideData} isActive={true} theme={theme}/>)}
{!currentSlideData && (<react_native_1.View style={styles.errorContainer}>
<react_native_1.Text style={styles.errorText}>Unable to load slide</react_native_1.Text>
</react_native_1.View>)}
</react_native_1.View>
{/* Footer with next button */}
<react_native_1.View style={styles.footer}>
<react_native_1.TouchableOpacity style={[
styles.nextButton,
{ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.buttonBackgroundColor) || '#6B8E5A' },
isLastSlide && styles.completeButton,
]} onPress={onNext} activeOpacity={0.8}>
<react_native_1.Text style={[
styles.nextButtonText,
{ color: (theme === null || theme === void 0 ? void 0 : theme.buttonTextColor) || 'white' },
isLastSlide && styles.completeButtonText,
]}>
{isLastSlide ? 'Get Started' : 'Next'}
</react_native_1.Text>
{!isLastSlide && (<vector_icons_1.Ionicons name="arrow-forward" size={20} color="white" style={styles.nextIcon}/>)}
</react_native_1.TouchableOpacity>
{!isLastSlide && (<react_native_1.Text style={styles.slideCounter}>
{currentSlide + 1} of {slides.length}
</react_native_1.Text>)}
</react_native_1.View>
</>)}
</react_native_1.SafeAreaView>
</react_native_1.Modal>);
};
const styles = react_native_1.StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F8FAF6',
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10,
height: 50,
},
headerSpacer: {
width: 32,
},
closeButton: {
padding: 4,
borderRadius: 20,
backgroundColor: 'rgba(0,0,0,0.05)',
},
progressContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 20,
gap: 8,
},
progressDot: {
height: 8,
borderRadius: 4,
},
slideContainer: {
flex: 1,
paddingHorizontal: 0,
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
errorText: {
fontSize: 16,
color: '#666',
textAlign: 'center',
},
footer: {
paddingHorizontal: 30,
paddingVertical: 30,
alignItems: 'center',
gap: 16,
},
nextButton: {
backgroundColor: '#6B8E5A',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 16,
paddingHorizontal: 32,
borderRadius: 25,
minWidth: width * 0.6,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
completeButton: {
backgroundColor: '#2F4F2F',
},
nextButtonText: {
color: 'white',
fontSize: 16,
fontWeight: '600',
},
completeButtonText: {
color: 'white',
},
nextIcon: {
marginLeft: 8,
},
slideCounter: {
fontSize: 14,
color: '#666',
textAlign: 'center',
},
paywallContainer: {
flex: 1,
},
});
exports.default = OnboardingModal;