| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- import {
- useImperativeHandle,
- useLayoutEffect,
- forwardRef,
- useEffect,
- useState,
- Fragment,
- useRef
- } from "react";
- import {
- Platform,
- Animated,
- Easing,
- View
- } from "react-native";
- import {
- type EmbeddedMenuButton as EmbeddedMenuButtonType
- } from "./components/menuButton/type";
- import {
- type IEmbeddedMenuRef
- } from "./type";
- import type IEmbeddedMenuProps from "./type";
- import stylesheet, {
- useStyles
- } from "./stylesheet";
- import MenuButton from "./components/menuButton";
- import {
- NCoreUIKitEmbeddedMenu,
- NCoreUIKitTheme
- } from "../../core/hooks";
- import type {
- RefForwardingComponent
- } from "../../types";
- import {
- PanelLeftClose,
- PanelLeftOpen
- } from "lucide-react-native";
- import {
- SafeAreaView
- } from "react-native-safe-area-context";
- import Seperator from "../seperator";
- import SiteLogo from "../siteLogo";
- import Button from "../button";
- const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
- isWorkWithSafeAreaView = true,
- isWorkWithHeaderSpace = true,
- isWorkWithAnimation = true,
- renderHeader: RenderHeader,
- renderFooter: RenderFooter,
- isShowSiteLogo = true,
- close: closeAction,
- customLocalize,
- maxWidth = 300,
- minWidth = 75,
- siteLogoProps,
- headerSpace,
- customTheme,
- navigation,
- isCollapse,
- onClosed,
- onOpened,
- buttons,
- onClose,
- onOpen,
- style,
- id,
- ...props
- }, ref) => {
- const {
- configs,
- colors,
- spaces
- } = NCoreUIKitTheme.useContext(customTheme);
- const [
- isActive,
- setIsActive
- ] = useState(false);
- const {
- headerContentContainer: headerContentContainerDynamicStyle,
- headerContainer: headerContainerDynamicStyle,
- collapseButton: collapseButtonDynamicStyle,
- seperator: seperatorDynamicStyle,
- container: containerDynamicStyle,
- siteLogo: siteLogoDynamicStyle
- } = useStyles({
- isCollapse: isActive,
- colors,
- spaces
- });
- const animatedX = useRef(new Animated.Value(!isCollapse ? minWidth : maxWidth)).current;
- useImperativeHandle(
- ref,
- () => ({
- close,
- open
- }),
- []
- );
- useEffect(() => {
- if(isCollapse !== undefined && isActive !== isCollapse) setIsActive(isCollapse);
- }, [isCollapse]);
- useLayoutEffect(() => {
- if(isActive) {
- if(onOpen) onOpen({
- id
- });
- if(Platform.OS !== "web") {
- if(onOpened) onOpened({
- id
- });
- } else if(isWorkWithAnimation) {
- openAnimation();
- } else {
- animatedX.setValue(maxWidth);
- if(onOpened) onOpened({
- id
- });
- }
- } else {
- if(onClose) onClose({
- id
- });
- if(isWorkWithAnimation && Platform.OS === "web") {
- closeAnimation();
- } else {
- animatedX.setValue(minWidth);
- if(onClosed) onClosed({
- id
- });
- }
- }
- }, [
- isActive
- ]);
- const open = () => {
- NCoreUIKitEmbeddedMenu.open({
- id
- });
- };
- const close = () => {
- NCoreUIKitEmbeddedMenu.close({
- id
- });
- };
- const openAnimation = () => {
- Animated.timing(animatedX, {
- useNativeDriver: Platform.OS !== "web",
- easing: Easing.linear,
- toValue: maxWidth,
- duration: 300
- }).start(({
- finished
- }) => {
- if(finished) {
- if(onOpened) onOpened({
- id
- });
- }
- });
- };
- const closeAnimation = () => {
- Animated.timing(animatedX, {
- useNativeDriver: Platform.OS !== "web",
- easing: Easing.linear,
- toValue: minWidth,
- duration: 300
- }).start(({
- finished
- }) => {
- if(finished) {
- if(onClosed) onClosed({
- id
- });
- }
- });
- };
- const updateMenuButtonCollabs = ({
- depthMap,
- status
- }: {
- depthMap: Array<number>;
- status: boolean;
- }) => {
- const state = NCoreUIKitEmbeddedMenu.get({
- id
- });
- if(!state) {
- return;
- }
- const recursivelyCatch = (item: Array<EmbeddedMenuButtonType>, index = 0): Array<EmbeddedMenuButtonType> => {
- const tIndex = depthMap[index];
- return item.map((c_item, c_index) => {
- if(c_index !== tIndex) {
- return c_item;
- }
- if(index === depthMap.length - 1) {
- return {
- ...c_item,
- isCollapse: status
- };
- }
- return {
- ...c_item,
- subButtons: recursivelyCatch(c_item.subButtons as Array<EmbeddedMenuButtonType>, index + 1)
- };
- });
- };
- const newButtons = recursivelyCatch(state.buttons);
- state.buttons = newButtons;
- NCoreUIKitEmbeddedMenu.update({
- menuData: state,
- id: id
- });
- };
- 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={() => {
- if(isActive) {
- close();
- } else {
- open();
- }
- }}
- />;
- };
- 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={() => {
- if(isActive) {
- close();
- } else {
- open();
- }
- }}
- />;
- };
- const renderHeader = () => {
- if(RenderHeader) {
- return <RenderHeader
- isCollapse={isActive}
- maxWidth={maxWidth}
- minWidth={minWidth}
- />;
- }
- return <View
- style={[
- stylesheet.headerContainer,
- headerContainerDynamicStyle
- ]}
- >
- {renderToggleCollapseForCollabsed()}
- <View
- style={[
- stylesheet.headerContentContainer,
- headerContentContainerDynamicStyle
- ]}
- >
- {isShowSiteLogo ? <SiteLogo
- customLocalize={customLocalize}
- customTheme={customTheme}
- {...siteLogoProps}
- title={isActive ? siteLogoProps?.title : undefined}
- size={isActive ? siteLogoProps?.size : "small"}
- style={[
- siteLogoProps?.style,
- siteLogoDynamicStyle
- ]}
- /> : <View
- style={{
- flex: 1
- }}
- />}
- {renderToggleCollapseForExpended()}
- </View>
- <Seperator
- style={[
- stylesheet.seperator,
- seperatorDynamicStyle
- ]}
- />
- </View>;
- };
- const renderButtons = () => {
- if(!buttons || !buttons.length) {
- return null;
- }
- 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}
- openMenu={() => {
- open();
- }}
- id={id}
- />;
- });
- };
- const renderFooter = () => {
- if(!RenderFooter) {
- return null;
- }
- return <RenderFooter
- isCollapse={isActive}
- maxWidth={maxWidth}
- minWidth={minWidth}
- />;
- };
- const renderSafeAreaContext = () => {
- if(!isWorkWithSafeAreaView) {
- return <Fragment>
- {isWorkWithHeaderSpace && (configs.headerSpace || headerSpace) ? <View
- style={{
- height: headerSpace ? headerSpace : configs.headerSpace,
- width: "100%"
- }}
- /> : null}
- {renderHeader()}
- <View
- style={[
- stylesheet.content
- ]}
- >
- {renderButtons()}
- </View>
- {renderFooter()}
- </Fragment>;
- }
- return <SafeAreaView
- style={[
- stylesheet.safeAreaView
- ]}
- >
- {renderHeader()}
- <View
- style={[
- stylesheet.content
- ]}
- >
- {renderButtons()}
- </View>
- {renderFooter()}
- </SafeAreaView>;
- };
- const renderContent = () => {
- return <Animated.View
- {...props}
- style={[
- style,
- stylesheet.container,
- containerDynamicStyle,
- Platform.OS === "web" ? {
- width: animatedX
- } : {
- width: isActive ? maxWidth : minWidth
- }
- ]}
- >
- {renderSafeAreaContext()}
- </Animated.View>;
- };
- return renderContent();
- };
- export default forwardRef(Menu);
|