-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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 positions when scrolling #22916
Conversation
* Use react-overlays built-in arrow positioning feature * Re-implemented `.dropdown-menu__arrow` to have a defined width and height to improve positioning * Moved wrapping div (`.dropdown-menu` from `DropdownMenu` to `Dropdown`) * Wrap button in a span to solve issue with ref * Temporarily remove animations
* Wrap EmojiPickerMenu in a div where react-overlays’ ref is added
This will take a while to properly review, but it looks good, thanks for your contribution! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<span ref={this.setTargetRef}> | ||
{button} | ||
</span> | ||
<Overlay show={open} offset={[5, 5]} placement={dropdownPlacement} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would make sense just removing the placement
logic and let react-overlays
handle it through the flip
prop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the placement
state from the individual components and also from the redux actions, so react-overlays is now handling all the positioning state.
<Overlay show={open} placement={placement} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed' }}> | ||
{({ props, placement }) => ( | ||
<div {...props} style={{ ...props.style, width: 350, maxWidth: '100vw' }}> | ||
<div className={`dropdown-animation ${placement}`}> | ||
<PrivacyDropdownMenu | ||
items={this.options} | ||
value={value} | ||
onClose={this.handleClose} | ||
onChange={this.handleChange} | ||
placement={placement} | ||
/> | ||
</div> | ||
</div> | ||
)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I resolved this by removing the z-index from .modal-root__modal
. z-index is already set to 9999 for .modal-root
so this does not appear to make any practical difference other than that the overlays are now working properly in the modals.
And remove the placement state from props of the menu components.
@ClearlyClaire Thanks for the review! I've solved the issues you commented on, but discovered an additional one when I got the dropdowns in the compose UI to flip properly. This issue is that the button for the privacy dropdown should take on the color of the adjacent option, and now that the react-overlays is handling the positioning we don't have the state available to apply the correct color to the button anymore. I'll request another review once I've fixed this. |
Copy the placement state into the `PrivacyDropdown` and `LanguageDropdown` components, to apply correct styling to the buttons depending on which placement the Overlay has.
Is this ready for another round of review? |
Yes, please go ahead! I've done another round of testing here and I think it's ready for another review. CI fails on lint, but from what I can see it's not on lines touched by this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have found no issue when testing, and I could only find one minor code issue. It should be fixed, but otherwise you can consider the PR approved.
Thank you for your contribution!
app/javascript/mastodon/features/compose/components/language_dropdown.js
Outdated
Show resolved
Hide resolved
/> | ||
<Overlay show={open} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}> | ||
{({ props, placement }) => ( | ||
<div {...props} style={{ ...props.style, width: 280 }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I just noticed that, but is there a way we can avoid such hardcoded values? The ideal width of the components depend on their text content, which depends on language, so it really should not be hardcoded.
This PR fixes #14266, an issue where dropdown positions, primarily in the compose UI, scroll together with the main timeline instead of staying fixed as expected. This is resolved by updating react-overlays from 0.9.3 to 5.2.1 (latest version as of today) and using
strategy: 'fixed'
inpopperConfig
.Here is an outline of the changes I have made.
DropdownMenu component:
.dropdown-menu__arrow
. The element needs to have a width and height be positioned correctly and this was easier than the previous approach with.dropdown-menu
fromDropdownMenu
toDropdown
).EmojiPickerDropdown, LanguageDropdown, PrivacyDropdown and SearchPopout components:
children
, setpopperConfig
,flip
andtarget
props.Everywhere:
@keyframes
animations to simplify the JavaScript code. No need to keep track of the mounted state to make the positioning of overlays work, or duplicate the animation parameters in multiple places in the codebase.Two thing to consider when reviewing this PR:
.dropdown-menu__arrow
) have been changed from being drawn with border-width to an inline SVG path, this will break any third-party CSS that relies on the border-width method. Not sure if this is a problem in practice.Any comments and feedback is very welcome!