|
|
@@ -14,12 +14,12 @@ import {
|
|
|
View
|
|
|
} from "react-native";
|
|
|
import {
|
|
|
- type MenuButton as MenuButtonType
|
|
|
+ type EmbeddedMenuButton as EmbeddedMenuButtonType
|
|
|
} from "./components/menuButton/type";
|
|
|
import {
|
|
|
- type IMenuRef
|
|
|
+ type IEmbeddedMenuRef
|
|
|
} from "./type";
|
|
|
-import type IMenuProps from "./type";
|
|
|
+import type IEmbeddedMenuProps from "./type";
|
|
|
import stylesheet, {
|
|
|
useStyles
|
|
|
} from "./stylesheet";
|
|
|
@@ -31,29 +31,28 @@ import {
|
|
|
import type {
|
|
|
RefForwardingComponent
|
|
|
} from "../../types";
|
|
|
+import {
|
|
|
+ PanelLeftClose,
|
|
|
+ PanelLeftOpen
|
|
|
+} from "lucide-react-native";
|
|
|
import {
|
|
|
SafeAreaView
|
|
|
} from "react-native-safe-area-context";
|
|
|
-import {
|
|
|
- Portal
|
|
|
-} from "../../helpers/portalize";
|
|
|
-import Modal from "../modal";
|
|
|
+import Button from "../button";
|
|
|
import Seperator from "../seperator";
|
|
|
import SiteLogo from "../siteLogo";
|
|
|
|
|
|
-const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
+const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
|
|
|
isWorkWithSafeAreaView = true,
|
|
|
isWorkWithAnimation = true,
|
|
|
renderHeader: RenderHeader,
|
|
|
renderFooter: RenderFooter,
|
|
|
- portalName = "menu-system",
|
|
|
- isWorkWithPortal = true,
|
|
|
- isWorkWithModal = true,
|
|
|
close: closeAction,
|
|
|
+ maxWidth = 300,
|
|
|
+ minWidth = 75,
|
|
|
siteLogoProps,
|
|
|
customTheme,
|
|
|
navigation,
|
|
|
- modalProps,
|
|
|
isCollabs,
|
|
|
onClosed,
|
|
|
onOpened,
|
|
|
@@ -69,31 +68,25 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
spaces
|
|
|
} = NCoreUIKitTheme.useContext(customTheme);
|
|
|
|
|
|
+ const [
|
|
|
+ isActive,
|
|
|
+ setIsActive
|
|
|
+ ] = useState(false);
|
|
|
+
|
|
|
const {
|
|
|
+ headerContentContainer: headerContentContainerDynamicStyle,
|
|
|
headerContainer: headerContainerDynamicStyle,
|
|
|
+ collapseButton: collapseButtonDynamicStyle,
|
|
|
seperator: seperatorDynamicStyle,
|
|
|
- container: containerDynamicStyle
|
|
|
+ container: containerDynamicStyle,
|
|
|
+ siteLogo: siteLogoDynamicStyle
|
|
|
} = useStyles({
|
|
|
+ isCollapse: isActive,
|
|
|
colors,
|
|
|
spaces
|
|
|
});
|
|
|
|
|
|
- const [
|
|
|
- isOpacityVisible,
|
|
|
- setIsOpacityVisible
|
|
|
- ] = useState(false);
|
|
|
-
|
|
|
- const [
|
|
|
- measures,
|
|
|
- setMeasures
|
|
|
- ] = useState<null | number>(null);
|
|
|
-
|
|
|
- const [
|
|
|
- isActive,
|
|
|
- setIsActive
|
|
|
- ] = useState(false);
|
|
|
-
|
|
|
- const animatedX = useRef(new Animated.Value(0)).current;
|
|
|
+ const animatedX = useRef(new Animated.Value(!isCollabs ? minWidth : maxWidth)).current;
|
|
|
|
|
|
useImperativeHandle(
|
|
|
ref,
|
|
|
@@ -104,22 +97,12 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
[]
|
|
|
);
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- if(measures !== null) {
|
|
|
- animatedX.setValue(measures * -1);
|
|
|
-
|
|
|
- if(!isOpacityVisible) setIsOpacityVisible(true);
|
|
|
-
|
|
|
- if(isActive) setIsActive(false);
|
|
|
- }
|
|
|
- }, [measures]);
|
|
|
-
|
|
|
useEffect(() => {
|
|
|
if(isCollabs !== undefined) setIsActive(isCollabs);
|
|
|
}, [isCollabs]);
|
|
|
|
|
|
useLayoutEffect(() => {
|
|
|
- if(isActive && isOpacityVisible) {
|
|
|
+ if(isActive) {
|
|
|
if(isWorkWithAnimation) {
|
|
|
openAnimation();
|
|
|
} else {
|
|
|
@@ -127,31 +110,28 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
id
|
|
|
});
|
|
|
|
|
|
- animatedX.setValue(0);
|
|
|
+ animatedX.setValue(maxWidth);
|
|
|
|
|
|
if(onOpened) onOpened({
|
|
|
id
|
|
|
});
|
|
|
}
|
|
|
} else {
|
|
|
- if(!isWorkWithModal) {
|
|
|
- if(isWorkWithAnimation) {
|
|
|
- closeAnimation();
|
|
|
- } else {
|
|
|
- if(onClose) onClose({
|
|
|
- id
|
|
|
- });
|
|
|
-
|
|
|
- animatedX.setValue(measures! * -1);
|
|
|
-
|
|
|
- if(onClosed) onClosed({
|
|
|
- id
|
|
|
- });
|
|
|
- }
|
|
|
+ if(isWorkWithAnimation) {
|
|
|
+ closeAnimation();
|
|
|
+ } else {
|
|
|
+ if(onClose) onClose({
|
|
|
+ id
|
|
|
+ });
|
|
|
+
|
|
|
+ animatedX.setValue(minWidth);
|
|
|
+
|
|
|
+ if(onClosed) onClosed({
|
|
|
+ id
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}, [
|
|
|
- isOpacityVisible,
|
|
|
isActive
|
|
|
]);
|
|
|
|
|
|
@@ -160,19 +140,7 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
};
|
|
|
|
|
|
const close = () => {
|
|
|
- if(isWorkWithModal) {
|
|
|
- if(isWorkWithAnimation) {
|
|
|
- closeAnimation();
|
|
|
- } else {
|
|
|
- animatedX.setValue(measures! * -1);
|
|
|
-
|
|
|
- if(onClosed) onClosed({
|
|
|
- id
|
|
|
- });
|
|
|
- }
|
|
|
- } else {
|
|
|
- setIsActive(false);
|
|
|
- }
|
|
|
+ setIsActive(false);
|
|
|
};
|
|
|
|
|
|
const openAnimation = () => {
|
|
|
@@ -183,8 +151,8 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
Animated.timing(animatedX, {
|
|
|
useNativeDriver: Platform.OS !== "web",
|
|
|
easing: Easing.linear,
|
|
|
- duration: 300,
|
|
|
- toValue: 0
|
|
|
+ toValue: maxWidth,
|
|
|
+ duration: 300
|
|
|
}).start(({
|
|
|
finished
|
|
|
}) => {
|
|
|
@@ -203,8 +171,8 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
|
|
|
Animated.timing(animatedX, {
|
|
|
useNativeDriver: Platform.OS !== "web",
|
|
|
- toValue: measures! * -1,
|
|
|
easing: Easing.linear,
|
|
|
+ toValue: minWidth,
|
|
|
duration: 300
|
|
|
}).start(({
|
|
|
finished
|
|
|
@@ -232,7 +200,7 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const recursivelyCatch = (item: Array<MenuButtonType>, index = 0): Array<MenuButtonType> => {
|
|
|
+ const recursivelyCatch = (item: Array<EmbeddedMenuButtonType>, index = 0): Array<EmbeddedMenuButtonType> => {
|
|
|
const tIndex = depthMap[index];
|
|
|
|
|
|
return item.map((c_item, c_index) => {
|
|
|
@@ -249,7 +217,7 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
|
|
|
return {
|
|
|
...c_item,
|
|
|
- subButtons: recursivelyCatch(c_item.subButtons as Array<MenuButtonType>, index + 1)
|
|
|
+ subButtons: recursivelyCatch(c_item.subButtons as Array<EmbeddedMenuButtonType>, index + 1)
|
|
|
};
|
|
|
});
|
|
|
};
|
|
|
@@ -264,9 +232,69 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+ const renderToggleCollapseForCollabsed = () => {
|
|
|
+ if(isActive) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return <Button
|
|
|
+ isCustomPadding={true}
|
|
|
+ spreadBehaviour="free"
|
|
|
+ type="neutral"
|
|
|
+ size="medium"
|
|
|
+ icon={({
|
|
|
+ color,
|
|
|
+ size
|
|
|
+ }) => {
|
|
|
+ return <PanelLeftOpen
|
|
|
+ color={colors.content.icon[color]}
|
|
|
+ size={size * 2}
|
|
|
+ />;
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ ...collapseButtonDynamicStyle
|
|
|
+ }}
|
|
|
+ onPress={() => {
|
|
|
+ setIsActive(!isActive);
|
|
|
+ }}
|
|
|
+ />;
|
|
|
+ };
|
|
|
+
|
|
|
+ const renderToggleCollapseForExpended = () => {
|
|
|
+ if(!isActive) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return <Button
|
|
|
+ isCustomPadding={true}
|
|
|
+ spreadBehaviour="free"
|
|
|
+ type="neutral"
|
|
|
+ size="medium"
|
|
|
+ icon={({
|
|
|
+ color,
|
|
|
+ size
|
|
|
+ }) => {
|
|
|
+ return <PanelLeftClose
|
|
|
+ color={colors.content.icon[color]}
|
|
|
+ size={size * 2}
|
|
|
+ />;
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ ...collapseButtonDynamicStyle
|
|
|
+ }}
|
|
|
+ onPress={() => {
|
|
|
+ setIsActive(!isActive);
|
|
|
+ }}
|
|
|
+ />;
|
|
|
+ };
|
|
|
+
|
|
|
const renderHeader = () => {
|
|
|
if(RenderHeader) {
|
|
|
- return <RenderHeader/>;
|
|
|
+ return <RenderHeader
|
|
|
+ isCollapse={isActive}
|
|
|
+ maxWidth={maxWidth}
|
|
|
+ minWidth={minWidth}
|
|
|
+ />;
|
|
|
}
|
|
|
|
|
|
return <View
|
|
|
@@ -275,9 +303,24 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
headerContainerDynamicStyle
|
|
|
]}
|
|
|
>
|
|
|
- <SiteLogo
|
|
|
- {...siteLogoProps}
|
|
|
- />
|
|
|
+ {renderToggleCollapseForCollabsed()}
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ stylesheet.headerContentContainer,
|
|
|
+ headerContentContainerDynamicStyle
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <SiteLogo
|
|
|
+ {...siteLogoProps}
|
|
|
+ title={isActive ? siteLogoProps?.title : undefined}
|
|
|
+ size={isActive ? siteLogoProps?.size : "small"}
|
|
|
+ style={[
|
|
|
+ siteLogoProps?.style,
|
|
|
+ siteLogoDynamicStyle
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ {renderToggleCollapseForExpended()}
|
|
|
+ </View>
|
|
|
<Seperator
|
|
|
style={[
|
|
|
stylesheet.seperator,
|
|
|
@@ -294,9 +337,11 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
|
|
|
return buttons.map((buttonItem, buttonIndex) => {
|
|
|
return <MenuButton
|
|
|
+ key={`embedded-menu-button-${id}-${buttonIndex}`}
|
|
|
updateMenuButtonCollabs={updateMenuButtonCollabs}
|
|
|
closeAction={closeAction}
|
|
|
buttonIndex={buttonIndex}
|
|
|
+ isMenuCollabs={isActive}
|
|
|
depthMap={[buttonIndex]}
|
|
|
buttonItem={buttonItem}
|
|
|
navigation={navigation}
|
|
|
@@ -310,13 +355,25 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- return <RenderFooter/>;
|
|
|
+ return <RenderFooter
|
|
|
+ isCollapse={isActive}
|
|
|
+ maxWidth={maxWidth}
|
|
|
+ minWidth={minWidth}
|
|
|
+ />;
|
|
|
};
|
|
|
|
|
|
const renderSafeAreaContext = () => {
|
|
|
if(!isWorkWithSafeAreaView) {
|
|
|
return <Fragment>
|
|
|
{renderHeader()}
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ stylesheet.content
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ {renderButtons()}
|
|
|
+ </View>
|
|
|
+ {renderFooter()}
|
|
|
</Fragment>;
|
|
|
}
|
|
|
|
|
|
@@ -345,46 +402,14 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
|
|
|
stylesheet.container,
|
|
|
containerDynamicStyle,
|
|
|
{
|
|
|
- opacity: isOpacityVisible ? 1 : 0,
|
|
|
- transform: [{
|
|
|
- translateX: animatedX
|
|
|
- }]
|
|
|
+ width: animatedX
|
|
|
}
|
|
|
]}
|
|
|
- onLayout={(event) => {
|
|
|
- const width = event.nativeEvent.layout.width;
|
|
|
-
|
|
|
- setMeasures(width);
|
|
|
- }}
|
|
|
>
|
|
|
{renderSafeAreaContext()}
|
|
|
</Animated.View>;
|
|
|
};
|
|
|
|
|
|
- if(isWorkWithModal && measures !== null) {
|
|
|
- return <Modal
|
|
|
- {...modalProps}
|
|
|
- isWorkWithPortal={isWorkWithPortal}
|
|
|
- isOverlayVisible={isOpacityVisible}
|
|
|
- onOverlayPress={() => {
|
|
|
- close();
|
|
|
- }}
|
|
|
- portalName={portalName}
|
|
|
- isActive={isActive}
|
|
|
- id="menu-modal"
|
|
|
- >
|
|
|
- {renderContent()}
|
|
|
- </Modal>;
|
|
|
- }
|
|
|
-
|
|
|
- if(isWorkWithPortal && measures !== null) {
|
|
|
- return <Portal
|
|
|
- name={portalName}
|
|
|
- >
|
|
|
- {renderContent()}
|
|
|
- </Portal>;
|
|
|
- }
|
|
|
-
|
|
|
return renderContent();
|
|
|
};
|
|
|
export default forwardRef(Menu);
|