cisco-sbg-ui / atomic-react

https://atomic-react.security.cisco.com
2 stars 5 forks source link

AMenu does not follow along with an anchor that is contained within an absolutely positioned element #1210

Open brennarvo opened 2 years ago

brennarvo commented 2 years ago

Describe the bug

The AMenu UI does not follow the trigger (.i.e., the anchorRef prop) when the containing element of the anchorRef is positioned as fixed.

A realistic instance of this problem is when AMenu is used in a header component with a positioned as fixed. Menus are often used to open actionable profile and account links.

To Reproduce

Steps to reproduce the behavior:

  1. Go to https://atomic-react.security.cisco.com/components/menu#usage
  2. Edit the playground code by adding a style={{ position: "fixed" }} to the most parent <div> element.
  3. Click any of the buttons
  4. With the menu opened, scroll down on the page

Expected behavior

The menu UI should follow along the trigger that is positioned as fixed.

Screenshots

Notice how the menu stays stuck while the triggers (the button elements) move down the page:

Screen Shot 2022-05-10 at 3 12 01 PM

Environment (please complete the following information):

Additional context

The menu is positioned correctly on the initial open, but any scrolling causes the bug. This has to do with the appRef and wrapRef variables, which most likely need to be updated in the positioning function to reflect the containing element which is positioned as fixed (how we do this elegantly is yet TBD).


Edit 1:

Adding a scroll event listener could resolve the issue, but updating an inlined style on every scroll is unideal for performance. See below for an example of 4x CPU demonstration (I know the demo looks a bit strange, but I needed a fixed anchor element (the button) to make this work):

https://user-images.githubusercontent.com/94568316/170145308-7838424b-f120-40bc-add7-3ce0fe8dfbdc.mov

Edit 2:

This will require AMenu to be positioned as fixed, which is something I'd rather have passed as compared to writing logical to determine if its parent is fixed.

paulmach commented 2 years ago

I was able to get this to work by wrapping an AMount

      <div style={{position: "fixed", zIndex: 10000}}>
        <AMount>
          <AButton
            ref={button1Ref}
            onClick={() => setOpen1(!open1)}
            aria-haspopup="true">
            Pivot Menu
          </AButton>
          <AMenu
            anchorRef={button1Ref}
            open={open1}
            placement="bottom"
            onClose={() => setOpen1(false)}
            pointer
            className="py-3">
            <AListItem twoLine className="px-3 h3 my-0 pb-1">
              <AListItemTitle>Bottom</AListItemTitle>
            </AListItem>
            <AListItem onClick={() => alert("alert1")} className="pl-3 py-1">
              Example
            </AListItem>
            <AListItem onClick={() => alert("alert2")} className="pl-3 py-1">
              Example
            </AListItem>
            <ADivider className="mb-0 mt-3" />
            <AListItem twoLine>
              <AListItemContent className="pb-0">
                <a onClick={() => alert("alert3")}>Connect</a>
              </AListItemContent>
            </AListItem>
          </AMenu>
        </AMount>
      </div>