UNPKG

@brijen/react-native-multistep

Version:

A lightweight multi-step view component for React Native with smooth transitions using Reanimated.

252 lines (250 loc) 8.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _reactNative = require("react-native"); var _react = _interopRequireWildcard(require("react")); var _Button = _interopRequireDefault(require("./Button.js")); var _ProgressCircle = _interopRequireDefault(require("./ProgressCircle.js")); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); var _Step = _interopRequireDefault(require("./Step.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * A multi-step container for managing step-based navigation. * It provides built-in navigation between steps with customizable buttons. * * @example * ```tsx * <MultiStep> * <Step title="Step 1"> * <Text>Content for Step 1</Text> * </Step> * <Step title="Step 2"> * <Text>Content for Step 2</Text> * </Step> * </MultiStep> * ``` */ const MultiStep = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => { const { children, prevButtonText, nextButtonText, prevButtonStyle, nextButtonStyle, prevButtonTextStyle, nextButtonTextStyle, prevButtonComponent, nextButtonComponent, tintColor, globalStepTitleStyle, globalNextStepTitleStyle, progressCircleSize, progressCircleThickness, progressCircleColor, progressCircleTrackColor, progressCircleLabelStyle, headerStyle, globalStepContainerStyle, fullScreenHeight, buttonContainerStyle, onFinalStepSubmit, submitButtonText, submitButtonTextStyle, submitButtonStyle, submitButtonComponent } = props; const COLOR = tintColor || '#DE3163'; const stepCount = _react.default.useMemo(() => _react.default.Children.count(children), [children]); const [currentStep, setCurrentStep] = (0, _react.useState)(0); const flatListRef = (0, _react.useRef)(null); const { width } = (0, _reactNative.useWindowDimensions)(); const nextStep = () => { if (currentStep < stepCount - 1) { setCurrentStep(prev => { const nextIndex = prev + 1; flatListRef.current?.scrollToIndex({ index: nextIndex, animated: true }); return nextIndex; }); } }; const prevStep = () => { if (currentStep > 0) { setCurrentStep(prev => { const prevIndex = prev - 1; flatListRef.current?.scrollToIndex({ index: prevIndex, animated: true }); return prevIndex; }); } }; (0, _react.useImperativeHandle)(ref, () => ({ nextStep, prevStep, scrollToStep: index => { if (index >= 0 && index < stepCount) { setCurrentStep(index); flatListRef.current?.scrollToIndex({ index, animated: true }); } } })); const { isValid, titles } = _react.default.useMemo(() => { const extractedTitles = []; let allValid = true; _react.default.Children.forEach(children, child => { if (! /*#__PURE__*/_react.default.isValidElement(child) || child.type !== _Step.default) { allValid = false; return; } extractedTitles.push({ title: child.props.title || '', stepTitleStyle: child.props.stepTitleStyle || {}, nextStepTitleStyle: child.props.nextStepTitleStyle || {}, titleComponent: child.props.titleComponent }); }); return { isValid: allValid, titles: extractedTitles }; }, [children]); if (!isValid) { if (__DEV__) console.error('MultiStep only accepts `Step` components as direct children.'); return null; } if (titles.length === 0) { if (__DEV__) console.error('MultiStep requires at least one Step component.'); return null; } const currentTitle = titles[currentStep]; const isFinalStep = currentStep === stepCount - 1; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.multiStepContainer, fullScreenHeight && { flex: 1 }], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.navigationHeader, headerStyle], children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.View, { style: styles.navigationItemWrapper, entering: _reactNativeReanimated.FadeInLeft.duration(300).easing(_reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.quad)), exiting: _reactNativeReanimated.FadeOutRight.duration(300).easing(_reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.quad)), children: [currentTitle?.titleComponent ? currentTitle.titleComponent : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.currentStepTect, { color: COLOR }, globalStepTitleStyle, currentTitle?.stepTitleStyle], children: currentTitle?.title }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: [styles.nextStepText, globalNextStepTitleStyle, currentTitle?.nextStepTitleStyle], children: currentStep < stepCount - 1 ? `Next: ${titles[currentStep + 1]?.title}` : 'Completion' })] }, currentStep), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ProgressCircle.default, { currentStep: currentStep + 1, totalSteps: titles.length, size: progressCircleSize, progressCircleThickness: progressCircleThickness, progressColor: progressCircleColor || COLOR, trackColor: progressCircleTrackColor, progressCircleLabelStyle: progressCircleLabelStyle })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.FlatList, { ref: flatListRef, data: _react.default.Children.toArray(children), horizontal: true, pagingEnabled: true, scrollEnabled: false, showsHorizontalScrollIndicator: false, keyExtractor: (_, index) => index.toString(), renderItem: ({ item }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.stepContainer, { width }, globalStepContainerStyle], children: item }), extraData: { currentStep, stepCount }, itemLayoutAnimation: _reactNativeReanimated.LinearTransition }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: [styles.buttonGroup, buttonContainerStyle], children: [prevButtonComponent ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, { title: prevButtonText || 'Back', variant: "secondary", tintColor: COLOR, style: prevButtonStyle, textStyle: prevButtonTextStyle, onPress: prevStep, disabled: currentStep === 0 }), !isFinalStep && (nextButtonComponent ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, { title: nextButtonText || 'Next', variant: "primary", tintColor: COLOR, style: nextButtonStyle, textStyle: nextButtonTextStyle, onPress: nextStep })), isFinalStep && (submitButtonComponent ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, { title: submitButtonText || 'Submit', variant: "primary", tintColor: COLOR, style: submitButtonStyle, textStyle: submitButtonTextStyle, onPress: onFinalStepSubmit }))] })] }); }); var _default = exports.default = MultiStep; const styles = _reactNative.StyleSheet.create({ multiStepContainer: { gap: 15 }, navigationHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 15, width: '100%', paddingHorizontal: 15 }, navigationItemWrapper: { flex: 1, gap: 10 }, stepContainer: { paddingHorizontal: 15 }, currentStepTect: { fontSize: 18, fontWeight: '600' }, nextStepText: { color: '#45474B' }, buttonGroup: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 15, marginTop: 10 } }); //# sourceMappingURL=MultiStep.js.map