Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collapsed sidebar-menu with one open sub-menu automatically opens tooltip menu of open sub-menu #17174

Open
jsefiani opened this issue Jun 19, 2019 · 13 comments

Comments

@jsefiani
Copy link

commented Jun 19, 2019

  • I have searched the issues of this repository and believe that this is not a duplicate.

Reproduction link

Edit on CodeSandbox

Steps to reproduce

Create a sidebar-menu that is collapsible with three sub-menus, each sub-menu (title prop has icon and text) has one menu item. (Check link for minimal reproduction, it's the exact problem that I'm facing)

Features:

  • Only one sub-menu can be opened at a time
  • Sidebar-menu can be collapsed
  • When the sidebar menu is collapsed, only the icons are visible
  • When I hover over an icon (in collapse mode), a tool tip is shown with the sub-menu's items (vertical)

Components:

  • Layout
  • Sider
  • Menu
  • Submenu
  • Menu.Item
  • Icon

What is expected?

Whenever I collapse the sidebar-menu with an open sub-menu, the sub-menu's tooltip is not shown automatically. The tooltip menu is only shown when I hover over the icon.

What is actually happening?

Whenever I collapse the sidebar-menu with an open sub-menu, the sub-menu's tooltip automatically pops up and only goes away when I hover over an icon of the sidebar menu.

Environment Info
antd 3.19.6
React 16.8.6
System Microsoft Windows 10 PRO
Browser Firefox developer edition 68.0b9 (64-bit)

When I collapse the sidebar menu without an open sub-menu, no menu tooltips are shown automatically which is the expected behavior.

@jsefiani

This comment has been minimized.

Copy link
Author

commented Aug 13, 2019

Any updates on this issue? @yutingzhao1991

@xyj404

This comment has been minimized.

Copy link

commented Aug 28, 2019

This bug still exist. Please give a response @yutingzhao1991

@xyj404

This comment has been minimized.

Copy link

commented Aug 28, 2019

It can be fixed by setting openKeys [] when collapsed. You can save previous openKeys, and set it to openKeys when expand.

      if (collapsed) {
        preOpenKeys.current = [...openKeys]
        setOpenKeys([]);
      } else {
        setOpenKeys(preOpenKeys.current);
      }

@jsefiani

This comment has been minimized.

Copy link
Author

commented Sep 3, 2019

Can you please give some more information? I'm already setting the openKeys property.

@LeeRayno

This comment has been minimized.

Copy link

commented Sep 18, 2019

@xyj404
But this experience is not good, there is a delay in the submenu hiding by setting openKeys [] when collapsed,not disappearing instantly.

@xyj404

This comment has been minimized.

Copy link

commented Sep 18, 2019

You can change openKeys and collapsed sync。

@LeeRayno

This comment has been minimized.

Copy link

commented Sep 18, 2019

@xyj404 how? can you show me the code
I put the collapsed in the react-redux and get it by the props and update when the collapsed changed

useEffect(() => {
    collapsed ? setOpenKeys([]) : setOpenKeys(matchRoutes(routes, pathname).map(item => item.path));
  }, [collapsed, pathname]);

here is my code

import React, { useState, useEffect } from 'react';
import { Menu, Icon } from 'antd';
import menus from 'config/menu.config';
import { withRouter } from 'react-router-dom';
import { matchRoutes, routes } from 'router/index';

const { SubMenu } = Menu;

function AppMenu(props) {
  const { history, collapsed, location: { pathname } } = props;

  const [rootSubmenuKeys] = useState(menus.map(item => item.path));
  const [openKeys, setOpenKeys] = useState(matchRoutes(routes, pathname).map(item => item.path) || []);
  const [selectedKeys, setSelectedKeys] = useState([]);

  useEffect(() => {
    setSelectedKeys([pathname]);
  }, [pathname]);

  useEffect(() => {
    collapsed ? setOpenKeys([]) : setOpenKeys(matchRoutes(routes, pathname).map(item => item.path));
  }, [collapsed, pathname]);

  const handleMenuClick = (v) => {
    history.push(v.key);
  };

  const handleOpenChange = (v) => {
    const latestOpenKey = v.find(key => openKeys.indexOf(key) === -1);
    if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
      setOpenKeys(v);
    } else {
      setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
    }
  };
  
  const renderMenuItem = (menu) => {
    const { title, path, icon, children, isLink } = menu;

    return (
      children ? renderSubMenuItem(menu) : (
        <Menu.Item key={path}>
          {icon && <Icon type={icon} />}
          {!isLink 
            ? <span>{title}</span> 
            : <a href={path} target="_blank" rel="noopener noreferrer">{title}</a>
          }
        </Menu.Item>
      )
    );
  };

  const renderSubMenuItem = (menu) => {
    const { title, icon, path, children } = menu;

    return (
      <SubMenu
        key={path}
        title={
          <span>
            {icon && <Icon type={icon} />}
            <span>{title}</span>
          </span>
        }
      >
        {
          children && children.map(child => {
            const copy = { ...child };
            copy.path = copy.isLink ? child.path : `${path}${child.path}`;

            return renderMenuItem(copy);
          })
        }
      </SubMenu>
    );
  };

  return (
    <Menu
      mode="inline"
      theme="dark"
      selectedKeys={selectedKeys}
      openKeys={openKeys}
      onClick={handleMenuClick}
      onOpenChange={handleOpenChange}
    >
      {
        menus.map(menu => renderMenuItem(menu))
      }
    </Menu>
  );
}

export default withRouter(AppMenu);
@xyj404

This comment has been minimized.

Copy link

commented Sep 18, 2019

You can send openKeys from parent component and let collapsed and openKeys changed sync.

@LeeRayno

This comment has been minimized.

Copy link

commented Sep 19, 2019

@xyj404 thank you, use the Lifting State Up, it works. but I don't understand why these code doesn't work

useEffect(() => {
    collapsed ? setOpenKeys([]) : setOpenKeys(matchRoutes(routes, pathname).map(item => item.path));
}, [collapsed, pathname]);

useEffect is async ? or when the collapsed changed and it excute the useEffect callback?

@xyj404

This comment has been minimized.

Copy link

commented Sep 19, 2019

Yes, when the collapsed changed and it excute the useEffect callback

@scarcoco

This comment has been minimized.

Copy link

commented Oct 11, 2019

...
   onOpenChange = (keys: string[]) => {
    prevOpenKeys = keys

    this.setState({
      openKeys: keys
    })
  }

  onToggleSider = () => {
    const { collapsed, openKeys } = this.state

    const state = {
      collapsed: !collapsed,
      openKeys
    }
    if (!collapsed) {
      prevOpenKeys = openKeys
      state.openKeys = []
    } else {
      state.openKeys = prevOpenKeys
    }
    this.setState(state)
  }
...

this can keep when just toggle menu, but loss some openkeys

@kairataliakbar

This comment has been minimized.

Copy link

commented Oct 14, 2019

it helped me

....
render() {
   let customProps = this.state.collapsed ? undefined : {
            openKeys: this.state.openKeys,
            onOpenChange = openKeys => {
                 const latestOpenKey = openKeys.find(
                      key => this.state.openKeys.indexOf(key) === -1
                  );
                  if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
                       this.setState({ openKeys });
                   } else {
                        this.setState({
                             openKeys: latestOpenKey ? [latestOpenKey] : []
                         });
                    }
              };
     }
     return (
     .....
     <Menu theme="dark" mode="inline" {...customProps}>
     .....
     );
}
....

@HieuDevX

This comment has been minimized.

Copy link

commented Oct 14, 2019

it helped me

....
render() {
   let customProps = this.state.collapsed ? undefined : {
            openKeys: this.state.openKeys,
            onOpenChange = openKeys => {
                 const latestOpenKey = openKeys.find(
                      key => this.state.openKeys.indexOf(key) === -1
                  );
                  if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
                       this.setState({ openKeys });
                   } else {
                        this.setState({
                             openKeys: latestOpenKey ? [latestOpenKey] : []
                         });
                    }
              };
     }
     return (
     .....
     <Menu theme="dark" mode="inline" {...customProps}>
     .....
     );
}
....

Can you select menu item in sub menu when menu collapsed (collapsed true) with this code? I try but it doesn't work :3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.