Skip to content

Conversation

filipw01
Copy link
Contributor

@filipw01 filipw01 commented Nov 16, 2022

Closes: relates to #1297

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Open newly created story in UseOverlayPosition story and play with different positions and offsets. More details about the issue that was fixed here #1297

🧢 Your Project:

https://www.chilipiper.com/

@filipw01 filipw01 marked this pull request as ready for review November 16, 2022 18:03
@filipw01 filipw01 changed the title Fix overlay position clamping @react-aria/overlays - Fix overlay position clamping Nov 16, 2022
@kwdowik
Copy link

kwdowik commented Nov 16, 2022

🚀

@snowystinger
Copy link
Member

GET_BUILD

@adobe-bot
Copy link

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

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

Thanks for having a go at this!

Comment on lines +206 to +209
// button bottom touching overlay bottom
let bottomsTouchPosition = childOffset[crossAxis] + childOffset[crossSize] - overlaySize[crossSize];
// button top touching overlay top
let topsTouchPosition = childOffset[crossAxis];
Copy link
Member

Choose a reason for hiding this comment

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

I'm a little worried about this, but potentially I'm just not holding the math in my head correctly because I've been testing locally and it appears to be correct.

It used to be that the min/max positions had to do with the center of the target and the top/bottom of the overlay, but now they'd be in relation to the top of the target and bottom of the target with the top and bottom of the overlay respectively?

I tried doing the storybook path=/story/dialogtrigger--crossoffset-examples and it looks right. I also tried it with much larger targets (UNSAFE_style height/width on the buttons) and it also still seems correct. Can you clarify the change a bit more?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, here is how it was calculated before

max = childOffset[crossAxis] + (childOffset[crossSize] / 2) - overlaySize[crossSize]
IMG_21C98B99B73F-1

min = childOffset[crossAxis] + (childOffset[crossSize] / 2)
IMG_00EF142400AF-1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is how it is calculated after my changes

topsTouch = childOffset[crossAxis]
IMG_8C5A6F6A8EE5-1

bottoms touch = childOffset[crossAxis] + childOffset[crossSize] - overlaySize[crossSize]
IMG_12D976EC8B0B-1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And we need to do the check at runtime which position is min and max because of this case
IMG_73BC5A43416C-1
IMG_C024DCCBE216-1

The old solution was glued to the middle of the button if the button was at least 2 times bigger than the overlay

.add('document.body container top', () => <Trigger withPortal placement="top" />)
.add('positioned container bottom', () => <Trigger withPortal={false} placement="bottom" />)
.add('positioned container top', () => <Trigger withPortal={false} placement="top" />)
.add('buttonWidth=500 document.body bottom start', () => <Trigger withPortal buttonWidth={500} placement="bottom start" />)
Copy link
Member

Choose a reason for hiding this comment

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

can you include a screenshot of before and after? just want to know what this is verifying

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is demonstrating the case where button is bigger than the overlay

Before:
Screenshot 2022-11-17 at 09 53 58

After:
Screenshot 2022-11-17 at 09 54 15

@filipw01
Copy link
Contributor Author

Here is also storybook path=/story/dialogtrigger--crossoffset-examples before and after changes

Before:
Screenshot 2022-11-17 at 09 56 47
Screenshot 2022-11-17 at 09 56 57

After:
Screenshot 2022-11-17 at 09 57 05
Screenshot 2022-11-17 at 09 57 09

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

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

Thanks so much for drawing those up, that really helped me understand the issue and what you were doing to solve it. This makes sense to me and does seem like a change we want. I've run into it in another bit of code of I've been working on and this would solve it.

Copy link
Member

@ktabors ktabors left a comment

Choose a reason for hiding this comment

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

Tested all the places where I expected issues and this works great. Thanks!
Love the diagrams!

Copy link
Member

@LFDanLu LFDanLu left a comment

Choose a reason for hiding this comment

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

LGTM, the calculations check out to me and the stories seem to reflect that

@LFDanLu LFDanLu merged commit e5d6994 into adobe:main Nov 18, 2022
LFDanLu added a commit that referenced this pull request Dec 14, 2022
@LFDanLu
Copy link
Member

LFDanLu commented Dec 14, 2022

Just a heads up, we have been discussing this new behavior amongst the team and haven't quite settled on what we want as the final behavior (in particular for the case where the overlay is smaller or equal to the trigger's size). We'll be reverting these changes for now so they won't be available in the release going out this month, but we plan on returning to this in the new year.

@filipw01
Copy link
Contributor Author

Thanks for the heads up. I was expecting the same/similar behavior to popper js, which was a dependency I removed in favor of react aria's positioning. Let me know if I can clarify anything

LFDanLu added a commit that referenced this pull request Dec 14, 2022
@LFDanLu
Copy link
Member

LFDanLu commented Jan 4, 2023

@filipw01 We did some more testing and these are the two cases which we wanted to fix/discuss:

  1. When the trigger is much larger than the overlay. Here the overlay arrow placement breaches the boundaries of the overlay if the crossOffset is set to a high enough value. When the cross offset exceeds that value, the arrow disappears entirely

image

image

  1. When the trigger is a similar size to the overlay. In the image below the cross offset is set to large value but the overlay only shifts a small amount due to how the boundary calculations work. Perhaps the overlay should shift in such a way that the its left/right edge is flush with the center arrow

image

Lemme know if you have any thoughts on the above and/or are interested in digging into these cases further. If not, that is perfectly fine, the team will see if we can address these cases in the coming sprints.

@filipw01
Copy link
Contributor Author

filipw01 commented Jan 9, 2023

@LFDanLu I'm still interested, I will take a closer look this week and let you know what I think about these cases

@filipw01
Copy link
Contributor Author

I think there are three main options here.

  1. Hide the arrow when the overlay is no longer next to the middle of the trigger, like the Arrow example on floating ui's page. I think this is the closest to what was implemented in this PR. With crossOffset, you could move the overlay as far as you want
  2. When the arrow reaches the boundary of the overlay, it starts moving together with the overlay, like the overflow prevention example on popper's page. As an accessibility-focused library, this might be a better option because you never see a detached overlay (if you use the arrow option). With crossOffset, you need at least an arrow width overlap between the trigger and overlay. If there is no arrow enabled, it can work the same as in option 1.
  3. When the arrow reaches the overlay boundary, don't move the overlay. With crossOffset, you need at least half trigger width and half arrow width overlap between the trigger and the overlay. If there is no arrow enabled, it can work the same as in option 1.

There are also possible hybrids like

  1. arrow follows the overlay like in option 2. but when it no longer overlaps, it is hidden like in option 1.
  2. when the arrow reaches the overlay boundary, it is hidden like in option 1.

I don't have a preference, and I don't know how hard it is to implement each option. Let me know what you think about these approaches.

@LFDanLu
Copy link
Member

LFDanLu commented Jan 13, 2023

@filipw01 Preliminary discussions with the team has us leaning towards option 2. One tricky thing is that we don't have the arrow's information (width, etc) available in calculatePosition. It is specified for the React Spectrum components in the css here, so we may need to move that variable to root and access it somewhere in the overlay position chain. If we don't detect that variable (aka non-RSP), we could have useOverlayPosition/calculatePosition accept a user defined option defining the arrow width.

I'll keep you posted with any further updates

LFDanLu added a commit that referenced this pull request Jan 18, 2023
@LFDanLu
Copy link
Member

LFDanLu commented Feb 2, 2023

@filipw01 The team has discussed this some more and would like to add an additional detail. We'd still like to go with option 2, but would like the arrow to always point to the center of the overlay if possible.
image

Let us know if you have any thoughts on the above

@filipw01
Copy link
Contributor Author

@LFDanLu Just so we're clear. You expect something like this, right?

image

@LFDanLu
Copy link
Member

LFDanLu commented Feb 15, 2023

@filipw01 Correct!

@filipw01
Copy link
Contributor Author

@LFDanLu I opened a new PR with changes to clamping and arrow position, check it out #4097

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants