Uh oh!
There was an error while loading. Please reload this page.
fix(SelectPanel): Correctly recalculate position on overflow - #5562
Conversation
🦋 Changeset detectedLatest commit: c874e45 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
👋 Hi, this pull request contains changes to the source code that github/github depends on. If you are GitHub staff, we recommend testing these changes with github/github using the integration workflow. Thanks! |
size-limit report 📦
|
Uh oh!
There was an error while loading. Please reload this page.
| const floatingElementRef = useProvidedRefOrCreate(settings?.floatingElementRef) | ||
| const anchorElementRef = useProvidedRefOrCreate(settings?.anchorElementRef) | ||
| const [position, setPosition] = React.useState<AnchorPosition | undefined>(undefined) | ||
| const [_, setPrevHeight] = React.useState<number | undefined>(undefined) |
There was a problem hiding this comment.
used to force the height of the selectPanel when filtered and it wants to shrink but it's anchored at the top (we want it to stay at the top and lock the height)
| if ( | ||
| settings?.pinPosition && | ||
| prev && | ||
| ['outside-top', 'inside-top'].includes(prev.anchorSide) && | ||
| (prev.anchorSide !== newPosition.anchorSide || prev.top < newPosition.top) |
There was a problem hiding this comment.
if the selectPanel is anchored to the top and it used to sit higher on the page....
| (prev.anchorSide !== newPosition.anchorSide || prev.top < newPosition.top) | ||
| ) { | ||
| const anchorTop = anchorElementRef.current?.getBoundingClientRect().top ?? 0 | ||
| if (anchorTop > (floatingElementRef.current?.clientHeight ?? 0)) { |
There was a problem hiding this comment.
if the anchorTop is bigger than the selectPanel's height, that means there is plenty of space for the selectPanel to stay at the top
| if (anchorTop > (floatingElementRef.current?.clientHeight ?? 0)) { | ||
| setPrevHeight(prevHeight => { | ||
| if (prevHeight && prevHeight > (floatingElementRef.current?.clientHeight ?? 0)) { | ||
| requestAnimationFrame(() => { |
There was a problem hiding this comment.
using requestAnimationFrame here to prevent a resizeObserver loop here due to us changing the element's height, but the observer listening for changes in the element...
| const anchorTop = anchorElementRef.current?.getBoundingClientRect().top ?? 0 | ||
| if (anchorTop > (floatingElementRef.current?.clientHeight ?? 0)) { | ||
| setPrevHeight(prevHeight => { | ||
| if (prevHeight && prevHeight > (floatingElementRef.current?.clientHeight ?? 0)) { |
There was a problem hiding this comment.
re-establish the height if it used to be bigger and is now attempting to shrink
| } else { | ||
| prev = newPosition |
There was a problem hiding this comment.
edgecase where the selectPanel is actually growing instead of shrinking, in this case we do want to allow it to recalculate/reposition
camertron
left a comment
There was a problem hiding this comment.
Wow, this is really good stuff, nice work! 🎉
I noticed a flicker in one of the after videos where the panel shrinks but then immediately grows again. What do you think it would take to remove the flicker?
| settings?.pinPosition && | ||
| prev && | ||
| ['outside-top', 'inside-top'].includes(prev.anchorSide) && | ||
| (prev.anchorSide !== newPosition.anchorSide || prev.top < newPosition.top) |
There was a problem hiding this comment.
Could we wrap this in a function and give it some comments so we know what's going on when we come back to the code in a few months?
| const anchorTop = anchorElementRef.current?.getBoundingClientRect().top ?? 0 | ||
| if (anchorTop > (floatingElementRef.current?.clientHeight ?? 0)) { |
There was a problem hiding this comment.
Same question: maybe wrap in a function with a nice, intention-revealing name and some comments?
emilybrick
left a comment
There was a problem hiding this comment.
Reviewing on behalf on design here - 👍
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
| alignmentOffset, | ||
| anchorOffset, | ||
| className, | ||
| pinPosition, |
There was a problem hiding this comment.
Should we add this to AnchoredOverlay.docs.json?
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
This reverts commit 8c1e8cf.
👋 Hi from github/github! Your integration PR is ready: https://github.com/github/github/pull/362265 |
🟢 golden-jobs completed with status |
👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks! |
francinelucca
commented
Feb 14, 2025
@camertron cleaned up the |
Closeshttps://github.com/github/primer/issues/4027
Continuation of #5207.
When the selectPanel grows after opening (example: open in loading state, data is fetched, items are rendered), the position is not recalculated and may cause content to go off screen (See for more context https://github.com/github/primer/issues/4027). This PR corrects that undesired behavior by recalculating the position of the overlay on size change. Additionally, bake in logic so that the overlay retains it's size on filtering when anchored to the top (to prevent the panel from repositioning itself too many times).
before
Screen.Recording.2025-02-05.at.6.18.57.PM.mov
Screen.Recording.2025-02-05.at.6.19.47.PM.mov
after
Screen.Recording.2025-02-05.at.6.26.39.PM.mov
Screen.Recording.2025-02-05.at.6.21.45.PM.mov
Changelog
New
pinPositionprop inAnchoredOverlayto prevent position shifting when sitting at the top of the anchor.max-height: 100vhdefault to AnchoredOverlay.widthoverlay prop inSelectPanelpinPositionto true in SelectPanel if height hasn't been set by useruseAnchoredPositionto watch for changes within the floating element (i.e., the overlay)Changed
useAnchoredPosition'supdatePositionfunction to prevent anchored element to unpin from the top when possible (dependent onpinPosition) propuseResizeObserverhookRollout strategy
Testing & Reviewing
Test new functionality in https://primer-88a2e13e51-13348165.drafts.github.io/storybook/?path=/story/components-selectpanel-examples--reposition-after-loading, https://primer-88a2e13e51-13348165.drafts.github.io/storybook/?path=/story/components-selectpanel-examples--select-panel-reposition-inside-dialog
Ensure default functionality still works as expected: https://primer-88a2e13e51-13348165.drafts.github.io/storybook/?path=/story/components-selectpanel--default
Merge checklist