-
Notifications
You must be signed in to change notification settings - Fork 650
experimental/SelectPanel: Update anchored position after showModal #4396
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
Changes from all commits
8456564
7e01470
2761316
0dc5ca9
15c0853
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@primer/react": patch | ||
| --- | ||
|
|
||
| exerimental/SelectPanel: Fix anchored position when close to the edge of browser window |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -164,11 +164,31 @@ const Panel: React.FC<SelectPanelProps> = ({ | |||||
| /* Dialog */ | ||||||
| const dialogRef = React.useRef<HTMLDialogElement>(null) | ||||||
|
|
||||||
| /* Anchored position */ | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for reviewer: This function already existed, just moved it above |
||||||
| const {position, updatePosition} = useAnchoredPosition( | ||||||
| { | ||||||
| anchorElementRef: anchorRef, | ||||||
| floatingElementRef: dialogRef, | ||||||
| side: 'outside-bottom', | ||||||
| align: 'start', | ||||||
| }, | ||||||
| [ | ||||||
| /* | ||||||
| Because we call dialog.showModal() to open the dialog, | ||||||
| we need to wait until the browser opens the dialog (giving it dimensions) | ||||||
| before updating position. (it is 0px by 0px until opened) | ||||||
| This is why we explicitly call updatePosition instead of using dependencies. | ||||||
| */ | ||||||
| ], | ||||||
| ) | ||||||
|
|
||||||
| // sync dialog open state (imperative) with internal component state | ||||||
| React.useEffect(() => { | ||||||
| if (internalOpen) dialogRef.current?.showModal() | ||||||
| else if (dialogRef.current?.open) dialogRef.current.close() | ||||||
| }, [internalOpen]) | ||||||
| if (internalOpen) { | ||||||
| dialogRef.current?.showModal() | ||||||
| updatePosition() // update the position once the dialog is open | ||||||
| } else if (dialogRef.current?.open) dialogRef.current.close() | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be inlined
Suggested change
|
||||||
| }, [internalOpen, updatePosition]) | ||||||
|
|
||||||
| // dialog handles Esc automatically, so we have to sync internal state | ||||||
| // but it doesn't call onCancel, so have another effect for that! | ||||||
|
|
@@ -202,17 +222,6 @@ const Panel: React.FC<SelectPanelProps> = ({ | |||||
| [internalOpen], | ||||||
| ) | ||||||
|
|
||||||
| /* Anchored */ | ||||||
| const {position} = useAnchoredPosition( | ||||||
| { | ||||||
| anchorElementRef: anchorRef, | ||||||
| floatingElementRef: dialogRef, | ||||||
| side: 'outside-bottom', | ||||||
| align: 'start', | ||||||
| }, | ||||||
| [internalOpen, anchorRef.current, dialogRef.current], | ||||||
| ) | ||||||
|
|
||||||
| /* | ||||||
| We want to cancel and close the panel when user clicks outside. | ||||||
| See decision log: https://github.com/github/primer/discussions/2614#discussioncomment-8544561 | ||||||
|
|
@@ -233,6 +242,10 @@ const Panel: React.FC<SelectPanelProps> = ({ | |||||
| maxHeight={maxHeight} | ||||||
| data-variant={currentVariant} | ||||||
| sx={{ | ||||||
| // to avoid a visible position shift, we delay the overlay animating-in | ||||||
| // to wait until the correct position is set (see useAnchoredPosition above for more) | ||||||
| animationDelay: '16ms', | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for reviewer: This isn't scientific at all, but we need to pick a number, so based it off a 60Hz refresh rate 😅 From https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame,
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative approach would be to "watch" for dialog open. Either in a recursive timeout or intersection observer, but that felt overkill! |
||||||
|
|
||||||
| '--max-height': heightMap[maxHeight], | ||||||
| // reset dialog default styles | ||||||
| border: 'none', | ||||||
|
|
||||||
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.
Note for reviewer: Need to add this if we want to delay animation