UNPKG

manuthecoder-react-native-spotlight-tour

Version:

React Native library to implement a highly customizable app tour feature with an awesome spotlight effect

122 lines 4.56 kB
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState, } from "react"; import { isChildFunction } from "../helpers/common"; import { SpotlightTourContext, ZERO_SPOT, } from "./SpotlightTour.context"; import { TourOverlay } from "./components/tour-overlay/TourOverlay.component"; /** * React provider component to get access to the SpotlightTour context. */ export const SpotlightTourProvider = forwardRef((props, ref) => { const { arrow, children, flip, motion = "bounce", nativeDriver = true, offset, onBackdropPress, onPause, onResume, onStop, overlayColor = "black", overlayOpacity = 0.45, placement, shape = "circle", shift, steps, } = props; const [current, setCurrent] = useState(); const [spot, setSpot] = useState(ZERO_SPOT); const [pausedAt, setPausedAt] = useState(); const overlay = useRef({ hideTooltip: () => Promise.resolve({ finished: false }), }); const status = useMemo(() => { if (current === undefined) { return pausedAt !== undefined ? "paused" : "idle"; } return "running"; }, [current, pausedAt]); const currentStep = useMemo(() => { const step = current !== undefined ? steps[current] : undefined; return step ?? { render: () => _jsx(_Fragment, {}) }; }, [steps, current]); const renderStep = useCallback((index) => { const step = steps[index]; if (step !== undefined) { Promise.all([ overlay.current.hideTooltip(), Promise.resolve().then(step.before), ]) .then(() => setCurrent(index)); } }, [steps]); const changeSpot = useCallback((newSpot) => { setSpot(newSpot); }, []); const start = useCallback(() => { renderStep(0); }, [renderStep]); const stop = useCallback(() => { setCurrent(prev => { if (prev !== undefined) { onStop?.({ index: prev, isLast: prev === steps.length - 1, }); } return undefined; }); setSpot(ZERO_SPOT); }, [onStop]); const next = useCallback(() => { if (current !== undefined) { current === steps.length - 1 ? stop() : renderStep(current + 1); } }, [stop, renderStep, current, steps.length]); const previous = useCallback(() => { if (current !== undefined && current > 0) { renderStep(current - 1); } }, [renderStep, current]); const goTo = useCallback((index) => { renderStep(index); }, [renderStep]); const pause = useCallback(() => { setCurrent(prev => { if (prev !== undefined) { setPausedAt(prev); onPause?.({ index: prev, isLast: prev === steps.length - 1, }); } return undefined; }); }, [onPause, steps.length]); const resume = useCallback(() => { const index = pausedAt ?? 0; const isLast = index === steps.length - 1; goTo(index); setPausedAt(undefined); onResume?.({ index, isLast }); }, [goTo, onResume, pausedAt, steps.length]); const tour = useMemo(() => ({ changeSpot, current, goTo, next, pause, previous, resume, spot, start, status, steps, stop, }), [changeSpot, current, goTo, next, previous, spot, start, steps, stop, pause]); useImperativeHandle(ref, () => ({ current, goTo, next, pause, previous, resume, start, status, stop, })); return (_jsxs(SpotlightTourContext.Provider, { value: tour, children: [isChildFunction(children) ? _jsx(SpotlightTourContext.Consumer, { children: children }) : _jsx(_Fragment, { children: children }), _jsx(TourOverlay, { backdropOpacity: overlayOpacity, color: overlayColor, current: current, motion: motion, nativeDriver: nativeDriver, onBackdropPress: onBackdropPress, ref: overlay, shape: shape, spot: spot, tourStep: currentStep, arrow: arrow, flip: flip, offset: offset, placement: placement, shift: shift })] })); }); //# sourceMappingURL=SpotlightTour.provider.js.map