UNPKG

react-native-actions-sheet

Version:

A Cross Platform(Android & iOS) ActionSheet with a robust and flexible api, native performance and zero dependency code for react native. Create anything you want inside ActionSheet.

233 lines (229 loc) 8.39 kB
import React, { createContext, useContext, useEffect, useRef, useState, } from 'react'; import { actionSheetEventManager } from './eventmanager'; export var providerRegistryStack = []; /** * An object that holds all the sheet components against their ids. */ export var sheetsRegistry = {}; // Registers your Sheet with the SheetProvider. export function registerSheet(id, Sheet) { /** * @deprecated Does nothing */ var _contexts = []; for ( /** * @deprecated Does nothing */ var _i = 2; /** * @deprecated Does nothing */ _i < arguments.length; /** * @deprecated Does nothing */ _i++) { /** * @deprecated Does nothing */ _contexts[_i - 2] = arguments[_i]; } if (!id || !Sheet) return; sheetsRegistry[id] = Sheet; actionSheetEventManager.publish('context-on-register'); } /** * The SheetProvider makes available the sheets in a given context. The default context is * `global`. However if you want to render a Sheet within another sheet or if you want to render * Sheets in a modal. You can use a seperate Provider with a custom context value. * * For example ```ts // Define your SheetProvider in the component/modal where // you want to show some Sheets. <SheetProvider context="local-context" /> // Then register your sheet when for example the // Modal component renders. registerSheet('local-sheet', LocalSheet,'local-context'); ``` * @returns */ export function SheetProvider(_a) { var _b = _a.context, context = _b === void 0 ? 'global' : _b, children = _a.children; var _c = useState(Object.keys(sheetsRegistry)), sheetIds = _c[0], setSheetIds = _c[1]; useEffect(function () { if (providerRegistryStack.indexOf(context) === -1) { providerRegistryStack.push(context); } else { if (__DEV__) { console.warn("You are trying to register multiple SheetProviders with the same context id: ".concat(context, ". Use a unique context id for each SheetProvider in your app.")); } } var onRegister = function () { setSheetIds(Object.keys(sheetsRegistry)); }; var sub = actionSheetEventManager.subscribe("context-on-register", onRegister); setSheetIds(Object.keys(sheetsRegistry)); return function () { var providerIndex = providerRegistryStack.indexOf(context); if (providerIndex > -1) { providerRegistryStack.splice(providerRegistryStack.indexOf(context), 1); } sub === null || sub === void 0 ? void 0 : sub.unsubscribe(); }; }, [context]); var renderSheet = React.useCallback(function (sheetId) { return (<RenderSheet key={sheetId + context} id={sheetId} context={context}/>); }, [context]); return (<ProviderContext.Provider value={context}> {children} {sheetIds.map(renderSheet)} </ProviderContext.Provider>); } var ProviderContext = createContext('global'); var SheetIDContext = createContext(undefined); export var SheetRefContext = createContext({}); var SheetPayloadContext = createContext(undefined); /** * Get id of the current context in which this component is rendered. */ export var useProviderContext = function () { return useContext(ProviderContext); }; /** * Get id of the current sheet in which the current component is rendered. */ export var useSheetIDContext = function () { return useContext(SheetIDContext); }; /** * Get the current Sheet's internal ref. * @returns */ export function useSheetRef(_id) { return useContext(SheetRefContext); } /** * Get the payload this sheet was opened with. * @returns */ export function useSheetPayload(_id) { return useContext(SheetPayloadContext); } var RenderSheet = function (_a) { var id = _a.id, context = _a.context; var _b = useState(), payload = _b[0], setPayload = _b[1]; var _c = useState(null), overrideProps = _c[0], setOverrideProps = _c[1]; var _d = useState(false), visible = _d[0], setVisible = _d[1]; var ref = useRef(null); var clearPayloadTimeoutRef = useRef(null); var Sheet = sheetsRegistry[id] || null; var visibleRef = useRef(false); visibleRef.current = visible; var snapIndex = useRef(undefined); useEffect(function () { if (visible) { actionSheetEventManager.publish("show_".concat(id), payload, context, snapIndex.current); } }, [context, id, payload, visible]); useEffect(function () { var onShow = function (data, ctx, overrideProps, snapIndexValue) { if (ctx === void 0) { ctx = 'global'; } if (ctx !== context) return; clearTimeout(clearPayloadTimeoutRef.current); setPayload(data); setOverrideProps(overrideProps); snapIndex.current = snapIndexValue; setVisible(true); }; var onClose = function (_data, ctx) { if (ctx === void 0) { ctx = 'global'; } if (context !== ctx) return; setVisible(false); clearTimeout(clearPayloadTimeoutRef.current); clearPayloadTimeoutRef.current = setTimeout(function () { setPayload(undefined); }, 50); }; var onHide = function (data, ctx) { if (ctx === void 0) { ctx = 'global'; } actionSheetEventManager.publish("hide_".concat(id), data, ctx); }; var onUpdate = function (data, ctx, overrideProps) { if (ctx === void 0) { ctx = 'global'; } if (ctx !== context || !visibleRef.current) return; clearTimeout(clearPayloadTimeoutRef.current); setPayload(data); setOverrideProps(overrideProps); }; var subs = [ actionSheetEventManager.subscribe("update_".concat(id), onUpdate), actionSheetEventManager.subscribe("show_wrap_".concat(id), onShow), actionSheetEventManager.subscribe("onclose_".concat(id), onClose), actionSheetEventManager.subscribe("hide_wrap_".concat(id), onHide), ]; return function () { subs.forEach(function (s) { return s.unsubscribe(); }); }; }, []); if (!Sheet) return null; return !visible ? null : (<SheetIDContext.Provider value={id}> <SheetRefContext.Provider value={ref}> <SheetPayloadContext.Provider value={payload}> <Sheet sheetId={id} payload={payload} overrideProps={overrideProps}/> </SheetPayloadContext.Provider> </SheetRefContext.Provider> </SheetIDContext.Provider>); }; /** * Registers the sheet components with the global Sheet registery allowing * you to open sheets from anywhere in the app. * * We recommend you to use this once in your app in your `<App/>` component. * * @example * ```tsx * import {SheetProvider, SheetDefinition} from "react-native-actions-sheet"; * * declare module 'react-native-actions-sheet' { * export interface Sheets { * 'example-sheet': SheetDefinition; * } * } * * const App = () => { * return <View> * <SheetRegister * sheets={ * "example-sheet": ExampleSheet * } * /> * </View> * } * ``` */ export function SheetRegister(props) { useEffect(function () { Object.keys(props.sheets).forEach(function (id) { if (!props.sheets[id]) { throw new Error("SheetRegistry trying to register ".concat(id, " that is not a React Component.")); } if (sheetsRegistry[id]) { if (__DEV__) { console.warn("SheetRegistry tried to register sheet with the same id ".concat(id, " multiple times. If you are registering Sheets will multiple SheetRegistery components, make sure the ids are unique.")); } return; } sheetsRegistry[id] = props.sheets[id]; }); actionSheetEventManager.publish('context-on-register'); return function () { Object.keys(props.sheets).forEach(function (id) { delete sheetsRegistry[id]; }); actionSheetEventManager.publish('context-on-register'); }; }, [props.sheets]); return null; }