Skip to content

Instantly share code, notes, and snippets.

@Aryk
Created April 7, 2020 15:02
Show Gist options
  • Save Aryk/132a746976d48c9959a9eef605217361 to your computer and use it in GitHub Desktop.
Save Aryk/132a746976d48c9959a9eef605217361 to your computer and use it in GitHub Desktop.
import React, {MutableRefObject, useContext, useLayoutEffect, useRef} from "react";
import {cast, types} from "mobx-state-tree";
import Animated from "react-native-reanimated";
import {observer} from "mobx-react";
import BottomSheet from "reanimated-bottom-sheet";
import {View, Icon} from "native-base";
import {includes} from "lodash";
import {TouchableWithoutFeedback} from "react-native";
type BottomSheetModalNameType = "networkSortOptions";
const bottomSheetModalNames: BottomSheetModalNameType[] = ["networkSortOptions"];
const ButtonSheetModalsStore = types.
model("ButtonSheetModalsStore", {
modalsRendered: types.array(types.enumeration<BottomSheetModalNameType>("modalsRendered", bottomSheetModalNames)),
}).actions(self => ({
addRenderBottomSheetModals: (bottomSheetModal: BottomSheetModalNameType) => {
if (!includes(self.modalsRendered, bottomSheetModal))
self.modalsRendered = cast(self.modalsRendered.concat(bottomSheetModal as BottomSheetModalNameType));
},
removeRenderBottomSheetModals: (bottomSheetModal: BottomSheetModalNameType) => {
if (includes(self.modalsRendered, bottomSheetModal))
self.modalsRendered = cast(self.modalsRendered.filter(r => r !== "networkSortOptions"));
},
}));
const bottomSheetModalsStore = ButtonSheetModalsStore.create({
modalsRendered: []
});
const useBottomSheetModal = (modalName: BottomSheetModalNameType) => {
const context = useContext(BottomSheetModalContext);
useLayoutEffect(() => {
bottomSheetModalsStore.addRenderBottomSheetModals(modalName);
return () => bottomSheetModalsStore.removeRenderBottomSheetModals(modalName);
}, []);
return context[modalName];
};
interface ICreateBottomSheetModal<K> {
height: number;
renderContent: (props: {bottomSheetModalToggler: IBottomSheetModalToggler} & K) => React.ReactNode;
}
const bottomSheetModalsComponents = {};
function createBottomSheetModal<K>(name: BottomSheetModalNameType, {height, renderContent}: ICreateBottomSheetModal<K>) {
const RenderContent = renderContent as any;
bottomSheetModalsComponents[name] = ({callbackNode, bottomSheetModalToggler}) => <BottomSheet
ref={bottomSheetModalToggler.ref}
snapPoints={[height, 0]}
initialSnap={1}
renderContent={() => <View style={{backgroundColor: "#FFF", width: "100%", height: "100%", flexDirection: "column"}}>
<Icon
name="drag-handle"
type="MaterialIcons"
style={{alignSelf: "center", color: "#CCC", fontSize: 50, height: 23, marginTop: -10}}
/>
<RenderContent bottomSheetModalToggler={bottomSheetModalToggler} />
</View>
}
borderRadius={10}
callbackNode={callbackNode}
/>;
}
interface IBottomSheetModalToggler {
ref: MutableRefObject<null>;
show: () => any;
hide: () => any;
}
type IBottomSheetModalTogglers = {
[name in BottomSheetModalNameType]: IBottomSheetModalToggler;
};
const BottomSheetModalContext = React.createContext(null);
const BottomSheetModalCollection = observer(({children, callbackNode, bottomSheetModalTogglers}) => <>
{bottomSheetModalsStore.modalsRendered.map(name => {
const Component = bottomSheetModalsComponents[name];
return <Component
bottomSheetModalToggler={bottomSheetModalTogglers[name]}
callbackNode={callbackNode}
key={name}
/>;
})}
<BottomSheetModalContext.Provider value={bottomSheetModalTogglers}>
{children}
</BottomSheetModalContext.Provider>
</>);
const BottomSheetModals = ({children}) => {
const animatedValue = new Animated.Value(1);
const bottomSheetModalTogglers = {} as IBottomSheetModalTogglers;
bottomSheetModalNames.forEach(name => {
const ref = useRef(null);
const show = () => ref.current?.snapTo(0);
const hide = () => ref.current?.snapTo(1);
bottomSheetModalTogglers[name] = {ref, show, hide};
});
const hideAllModals = () =>
bottomSheetModalsStore.modalsRendered.forEach(name => bottomSheetModalTogglers[name].hide());
return <>
<Animated.View
style={{
opacity: Animated.multiply(Animated.sub(1, animatedValue), 0.7),
backgroundColor: "black",
left: 0,
top: 0,
// Make sure dark screen goes under everything when not active.
zIndex: Animated.cond(Animated.lessThan(animatedValue, 1), 1, 0),
width: "100%",
height: "100%",
position: "absolute"
}}
>
<TouchableWithoutFeedback onPress={hideAllModals} >
<View style={{width: "100%", height: "100%"}} />
</TouchableWithoutFeedback>
</Animated.View>
<BottomSheetModalCollection callbackNode={animatedValue} {...{bottomSheetModalTogglers}}>
{children}
</BottomSheetModalCollection>
</>;
};
export { BottomSheetModals, createBottomSheetModal, useBottomSheetModal, bottomSheetModalsStore,
bottomSheetModalNames, BottomSheetModalNameType, BottomSheetModalContext };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment