react-native-trays
Version:
Production-grade, Family inspired, React Native Tray System library
134 lines (133 loc) • 4.29 kB
JavaScript
;
/**
* TrayProvider.tsx
*
* Provides the TrayProvider React context component for managing tray stacks and rendering trays in a React Native app.
* This file contains the core logic for tray registration, stack management, and context propagation.
*/
import React, { useCallback, useMemo, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { FadeIn, FadeOut } from 'react-native-reanimated';
let BlurView = null;
try {
BlurView = require('expo-blur').BlurView;
} catch (e) {
BlurView = null;
}
import Animated from 'react-native-reanimated';
import uuid from 'react-native-uuid';
import { TrayContext } from "./context.js";
import { TrayStackRenderer } from "./TrayStackRenderer.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const defaultStackConfig = {
backdropStyles: {},
trayStyles: {},
adjustForKeyboard: true,
horizontalSpacing: 20,
dismissOnBackdropPress: true
};
/**
* TrayProvider: Manages tray stacks, context, and rendering.
*
* @template T - The tray registry type.
* @param trays - An object mapping tray keys to their components.
* @param children - React children to render inside the provider.
* @param stackConfigs - Optional per-stack configuration overrides.
*
* Provides context to manage multiple, optionally-configurable tray stacks and their lifecycle.
*/
export const TrayProvider = ({
trays,
children,
stackConfigs = {}
}) => {
const [stackMap, setStackMap] = useState({});
const modifyStack = useCallback((stackId, updater) => {
setStackMap(prev => {
const updated = updater(prev[stackId] || []);
if (!updated || updated.length === 0) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {
[stackId]: _,
...rest
} = prev;
return rest;
}
return {
...prev,
[stackId]: updated
};
});
}, []);
const push = useCallback((stackId, trayKey, props) => {
modifyStack(stackId, stack => [...stack, {
id: uuid.v4().toString(),
tray: trayKey,
stackId,
props
}]);
}, [modifyStack]);
const contextValue = useCallback(stackId => ({
push: (trayKey, props) => push(stackId, trayKey, props),
pop: () => modifyStack(stackId, stack => stack.slice(0, -1)),
replaceById: (trayId, props) => modifyStack(stackId, stack => stack.map(t => t.id === trayId ? {
...t,
props
} : t)),
replace: (trayKey, props) => modifyStack(stackId, stack => stack.map(t => t.tray === trayKey ? {
...t,
props
} : t)),
dismissById: trayId => modifyStack(stackId, stack => stack.filter(t => t.id !== trayId)),
dismiss: trayKey => modifyStack(stackId, stack => stack.filter(t => t.tray !== trayKey)),
dismissAll: () => setStackMap(prev => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {
[stackId]: _,
...rest
} = prev;
return rest;
})
}), [push, modifyStack]);
const activeStacks = useMemo(() => Object.entries(stackMap), [stackMap]);
return /*#__PURE__*/_jsxs(TrayContext.Provider, {
value: contextValue,
children: [children, activeStacks.map(([stackId, stack]) => /*#__PURE__*/_jsxs(React.Fragment, {
children: [/*#__PURE__*/_jsx(Animated.View, {
style: [styles.backdrop, stackConfigs[stackId]?.backdropStyles],
entering: FadeIn,
exiting: FadeOut,
onTouchEnd: () => {
contextValue(stackId).pop();
},
children: BlurView && !stackConfigs[stackId]?.disableBackgroundBlur ? /*#__PURE__*/_jsx(BlurView, {
style: styles.blurView,
...(stackConfigs[stackId]?.blurViewProps ?? {})
}) : /*#__PURE__*/_jsx(View, {
style: styles.blurViewPlaceholder
})
}), /*#__PURE__*/_jsx(TrayStackRenderer, {
stack: stack,
config: stackConfigs[stackId] || defaultStackConfig,
trays: trays
})]
}, stackId))]
});
};
const styles = StyleSheet.create({
backdrop: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 998
},
blurView: {
flex: 1
},
blurViewPlaceholder: {
flex: 1
}
});
//# sourceMappingURL=TrayProvider.js.map