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

Fix dropdown menu position in playground when scroll #4496

Merged

Conversation

xinyuan0801
Copy link
Contributor

Summary

This Pull Request introduces a fix to maintain the dropdown menu's position relative to the toolbar during page scroll. Previously, the dropdown menu was using position: fixed, causing it to remain stationary in the viewport instead of moving along with the toolbar during scrolling.

How to reproduce

adding content in the playground editor untill a scroll bar appear, and then open any dropdown menu in the toolbar and scroll the page.

Details

The dropdown menu's positioning logic has been updated to become fixed or absolute based on the toolbar's position.

Important Note

Obtaining an accurate toolbar position is crucial for this logic. However, due to asynchronous loading of elements (like the Logo), directly extracting the toolbar's position in a useEffect hook can result in inaccurate values. To ensure precision, we're extracting the toolbar position asynchronously, which guarantees the correct calculation after all page elements have fully loaded. This is done by using setTimeout which could be consider a bad paractise, so any advice on extracting the toolbar position without using it is very appreciated.

@vercel
Copy link

vercel bot commented May 14, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lexical ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 19, 2023 3:02am
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 19, 2023 3:02am

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 14, 2023
Copy link
Member

@zurfyx zurfyx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, while this works it makes the Dropdown module lose it's reusability aspect as you're including the toolbar height in the computations.

We should be able to fix this retaining the position: fixed and a transform: translate(x, y) that moves as you scroll, looking at the nearest scroll parent and intersection (to handle visibility).

}: {
children: React.ReactNode;
dropDownRef: React.Ref<HTMLDivElement>;
onClose: () => void;
initialPosition: React.RefObject<number>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that dropdownRef should be sufficient to reposition accordingly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some scenarios, our current setup falls short. Consider this: when a user opens the dropdown menu while the toolbar is already sticky at the top of the page, we only get 44px as information. This doesn't tell us when the dropdown should start moving down the page as the user scrolls back up. So we need toolbar's initial position in order to solve that case. To figure out the toolbar's initial position, we need to capture this information right after the first render. That's why I'm proposing to pass in the initialPosition.

@xinyuan0801
Copy link
Contributor Author

Thank you, while this works it makes the Dropdown module lose it's reusability aspect as you're including the toolbar height in the computations.

We should be able to fix this retaining the position: fixed and a transform: translate(x, y) that moves as you scroll, looking at the nearest scroll parent and intersection (to handle visibility).

Hello, I believe that in the DropDown.tsx file, the dependency on toolbar height was already established prior to this Pull Request.

useEffect(() => {
    const button = buttonRef.current;
    const dropDown = dropDownRef.current;

    if (showDropDown && button !== null && dropDown !== null) {
      const {top, left} = button.getBoundingClientRect();
      dropDown.style.top = `${top + 40}px`;
      dropDown.style.left = `${Math.min(
        left,
        window.innerWidth - dropDown.offsetWidth - 20,
      )}px`;
    }
  }, [dropDownRef, buttonRef, showDropDown]);

it is the useEffect hook in DropDown component and it is used for calculating the position of dropdown menu when it is shown, and 40 here is the height of toolbar. I can try to solve that as well if needed.

I will also take a look at solving it using transform: translate(x, y), thank you for the advice!

@zurfyx
Copy link
Member

zurfyx commented May 18, 2023

the dependency on toolbar height was already established prior to this Pull Request.

You're right

we need toolbar's initial position in order to solve that case

But do we need a strong dependency with the toolbar? My hunch is that we can build a component that is able to render a dropdown {above|before|after|below} a HTML ref. The dropdown should reposition when you scroll or resize the page to stick to the same position as the component is.

@xinyuan0801
Copy link
Contributor Author

the dependency on toolbar height was already established prior to this Pull Request.

You're right

we need toolbar's initial position in order to solve that case

But do we need a strong dependency with the toolbar? My hunch is that we can build a component that is able to render a dropdown {above|before|after|below} a HTML ref. The dropdown should reposition when you scroll or resize the page to stick to the same position as the component is.

Hello, I realized that the initial position is indeed unnecessary and I've been able to simplify the solution. The latest changes have been committed, where the dropdown component no longer depends on the button's height being set to 40px and can be accurately positioned in relation to the button element.

I also took note of issue #4516 and concur that components such as dropdowns, modals, and buttons aren't central to a rich text editor framework. Until the core team settles on the direction to take - be it utilizing external libraries or developing in-house components - alterations to the playground code should be primarily directed towards rectifying existing bugs, instead of expanding the functionalities of current components. This PR is meant for a quick fix to improve the lexical playground user experience so I believe that addressing the dropdown's positioning within this very PR should suffice for the moment.

@thegreatercurve thegreatercurve merged commit b364470 into facebook:main Jun 19, 2023
@zurfyx zurfyx mentioned this pull request Jul 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants