|
|
@@ -0,0 +1,257 @@
|
|
|
+import {
|
|
|
+ useImperativeHandle,
|
|
|
+ useLayoutEffect,
|
|
|
+ forwardRef,
|
|
|
+ useEffect,
|
|
|
+ useState,
|
|
|
+ useRef
|
|
|
+} from "react";
|
|
|
+import {
|
|
|
+ Animated,
|
|
|
+ Easing,
|
|
|
+ View
|
|
|
+} from "react-native";
|
|
|
+import type {
|
|
|
+ IMenuRef
|
|
|
+} from "./type";
|
|
|
+import type IMenuProps from "./type";
|
|
|
+import stylesheet, {
|
|
|
+ useStyles
|
|
|
+} from "./stylesheet";
|
|
|
+import {
|
|
|
+ NCoreUIKitTheme
|
|
|
+} from "../../core/hooks";
|
|
|
+import type {
|
|
|
+ RefForwardingComponent
|
|
|
+} from "../../types";
|
|
|
+import Modal from "../modal";
|
|
|
+import {
|
|
|
+ Portal
|
|
|
+} from "../../helpers/portalize";
|
|
|
+
|
|
|
+const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
+ portalName = "menu-system",
|
|
|
+ isWorkWithAnimation = true,
|
|
|
+ isWorkWithPortal = true,
|
|
|
+ isWorkWithModal = true,
|
|
|
+ customTheme,
|
|
|
+ modalProps,
|
|
|
+ isCollabs,
|
|
|
+ onClosed,
|
|
|
+ onOpened,
|
|
|
+ onClose,
|
|
|
+ onOpen,
|
|
|
+ style,
|
|
|
+ id,
|
|
|
+ ...props
|
|
|
+}, ref) => {
|
|
|
+ const {
|
|
|
+ colors,
|
|
|
+ spaces
|
|
|
+ } = NCoreUIKitTheme.useContext(customTheme);
|
|
|
+
|
|
|
+ const {
|
|
|
+ container: containerDynamicStyle
|
|
|
+ } = useStyles({
|
|
|
+ colors,
|
|
|
+ spaces
|
|
|
+ });
|
|
|
+
|
|
|
+ const [
|
|
|
+ isOpacityVisible,
|
|
|
+ setIsOpacityVisible
|
|
|
+ ] = useState(false);
|
|
|
+
|
|
|
+ const [
|
|
|
+ measures,
|
|
|
+ setMeasures
|
|
|
+ ] = useState<null | number>(null);
|
|
|
+
|
|
|
+ const [
|
|
|
+ isActive,
|
|
|
+ setIsActive
|
|
|
+ ] = useState(measures === null ? true : isCollabs);
|
|
|
+
|
|
|
+ const animatedX = useRef(new Animated.Value(0)).current;
|
|
|
+ console.log("aha da ranza:", id);
|
|
|
+ useImperativeHandle(
|
|
|
+ ref,
|
|
|
+ () => ({
|
|
|
+ close,
|
|
|
+ open
|
|
|
+ }),
|
|
|
+ []
|
|
|
+ );
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ console.log("z", new Date().toISOString());
|
|
|
+ if(measures !== null) {
|
|
|
+ animatedX.setValue(measures * -1);
|
|
|
+
|
|
|
+ if(!isOpacityVisible) setIsOpacityVisible(true);
|
|
|
+ console.log("x", new Date().toISOString());
|
|
|
+ if(isActive) setIsActive(false);
|
|
|
+ }
|
|
|
+ }, [measures]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ console.log("y", new Date().toISOString(), isCollabs);
|
|
|
+ setIsActive(isCollabs);
|
|
|
+ }, [isCollabs]);
|
|
|
+
|
|
|
+ useLayoutEffect(() => {
|
|
|
+ if(isActive && isOpacityVisible) {
|
|
|
+ if(isWorkWithAnimation) {
|
|
|
+ openAnimation();
|
|
|
+ } else {
|
|
|
+ if(onOpen) onOpen({
|
|
|
+ id
|
|
|
+ });
|
|
|
+
|
|
|
+ animatedX.setValue(0);
|
|
|
+
|
|
|
+ if(onOpened) onOpened({
|
|
|
+ id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if(!isWorkWithModal) {
|
|
|
+ if(isWorkWithAnimation) {
|
|
|
+ closeAnimation();
|
|
|
+ } else {
|
|
|
+ if(onClose) onClose({
|
|
|
+ id
|
|
|
+ });
|
|
|
+
|
|
|
+ animatedX.setValue(measures! * -1);
|
|
|
+
|
|
|
+ if(onClosed) onClosed({
|
|
|
+ id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [
|
|
|
+ isOpacityVisible,
|
|
|
+ isActive
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const open = () => {
|
|
|
+ setIsActive(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const close = () => {
|
|
|
+ if(isWorkWithModal) {
|
|
|
+ if(isWorkWithAnimation) {
|
|
|
+ closeAnimation();
|
|
|
+ } else {
|
|
|
+ animatedX.setValue(measures! * -1);
|
|
|
+
|
|
|
+ if(onClosed) onClosed({
|
|
|
+ id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ setIsActive(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const openAnimation = () => {
|
|
|
+ if(onOpen) onOpen({
|
|
|
+ id
|
|
|
+ });
|
|
|
+
|
|
|
+ Animated.timing(animatedX, {
|
|
|
+ useNativeDriver: true,
|
|
|
+ easing: Easing.linear,
|
|
|
+ duration: 300,
|
|
|
+ toValue: 0
|
|
|
+ }).start(({
|
|
|
+ finished
|
|
|
+ }) => {
|
|
|
+ if(finished) {
|
|
|
+ if(onOpened) onOpened({
|
|
|
+ id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const closeAnimation = () => {
|
|
|
+ if(onClose) onClose({
|
|
|
+ id
|
|
|
+ });
|
|
|
+
|
|
|
+ Animated.timing(animatedX, {
|
|
|
+ toValue: measures! * -1,
|
|
|
+ useNativeDriver: true,
|
|
|
+ easing: Easing.linear,
|
|
|
+ duration: 300
|
|
|
+ }).start(({
|
|
|
+ finished
|
|
|
+ }) => {
|
|
|
+ if(finished) {
|
|
|
+ if(onClosed) onClosed({
|
|
|
+ id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const renderContent = () => {
|
|
|
+ return <Animated.View
|
|
|
+ {...props}
|
|
|
+ style={[
|
|
|
+ style,
|
|
|
+ stylesheet.container,
|
|
|
+ containerDynamicStyle,
|
|
|
+ {
|
|
|
+ opacity: isOpacityVisible ? 1 : 0,
|
|
|
+ transform: [{
|
|
|
+ translateX: animatedX
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ onLayout={(event) => {
|
|
|
+ const width = event.nativeEvent.layout.width;
|
|
|
+
|
|
|
+ setMeasures(width);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ backgroundColor: "red",
|
|
|
+ height: 300,
|
|
|
+ width: 100
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Animated.View>;
|
|
|
+ };
|
|
|
+
|
|
|
+ if(isWorkWithModal) {
|
|
|
+ return <Modal
|
|
|
+ {...modalProps}
|
|
|
+ isWorkWithPortal={isWorkWithPortal}
|
|
|
+ isOverlayVisible={isOpacityVisible}
|
|
|
+ onOverlayPress={() => {
|
|
|
+ close();
|
|
|
+ }}
|
|
|
+ portalName={portalName}
|
|
|
+ isActive={isActive}
|
|
|
+ id="menu-modal"
|
|
|
+ >
|
|
|
+ {renderContent()}
|
|
|
+ </Modal>;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(isWorkWithPortal) {
|
|
|
+ return <Portal
|
|
|
+ name={portalName}
|
|
|
+ >
|
|
|
+ {renderContent()}
|
|
|
+ </Portal>;
|
|
|
+ }
|
|
|
+
|
|
|
+ return renderContent();
|
|
|
+};
|
|
|
+export default forwardRef(Menu);
|