-
Notifications
You must be signed in to change notification settings - Fork 272
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: use popper to properly position message actions box (#2241)
### 🎯 Goal Message actions box is currently relatively positioned inside MessageList, which means it sometimes gets clipped by MessageList's boundaries. This PR implements proper positioning for the actions box, preventing it from being clipped in (almost) every case. ### 🛠 Implementation details `stream-chat-react` already uses `react-popper` for tooltips, so it made sense to reuse it for the actions box as well. My initial plan was to render the actions box into a portal and position it using popper, but using a portal turned out to be unnecessary: with the positioning strategies that popper implements, the action box is never clipped by it's parent container. See also: GetStream/stream-chat-css#260 ### 🎨 UI Changes Previously: ![image](https://github.com/GetStream/stream-chat-react/assets/975978/cbeb3f34-7e4d-45bc-94f3-0473b376db76) ![image](https://github.com/GetStream/stream-chat-react/assets/975978/6a71ef77-47b6-42c5-b45c-20c01d114d35) After the fixes: The actions box automatically flips if it's close to the clipping boundary: ![image](https://github.com/GetStream/stream-chat-react/assets/975978/605a99c7-d2dd-4a7a-b039-69918fc444b7) ![image](https://github.com/GetStream/stream-chat-react/assets/975978/df6ab182-8d8a-4992-8323-9ddafbf51742) ### ✅ To-Do - [x] Check with all message types - [x] Check with Angular app - [x] ~~Deal with theming v1~~ - [x] ~~Fix E2E~~
- Loading branch information
1 parent
a95f3b5
commit 651d3e7
Showing
5 changed files
with
122 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useMessageActionsBoxPopper'; |
45 changes: 45 additions & 0 deletions
45
src/components/MessageActions/hooks/useMessageActionsBoxPopper.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { Placement } from '@popperjs/core'; | ||
import { useEffect, useRef } from 'react'; | ||
import { usePopper } from 'react-popper'; | ||
|
||
export interface MessageActionsBoxPopperOptions { | ||
open: boolean; | ||
placement: Placement; | ||
referenceElement: HTMLElement | null; | ||
} | ||
|
||
export function useMessageActionsBoxPopper<T extends HTMLElement>({ | ||
open, | ||
placement, | ||
referenceElement, | ||
}: MessageActionsBoxPopperOptions) { | ||
const popperElementRef = useRef<T>(null); | ||
const { attributes, styles, update } = usePopper(referenceElement, popperElementRef.current, { | ||
modifiers: [ | ||
{ | ||
name: 'eventListeners', | ||
options: { | ||
// It's not safe to update popper position on resize and scroll, since popper's | ||
// reference element might not be visible at the time. | ||
resize: false, | ||
scroll: false, | ||
}, | ||
}, | ||
], | ||
placement, | ||
}); | ||
|
||
useEffect(() => { | ||
if (open) { | ||
// Since the popper's reference element might not be (and usually is not) visible | ||
// all the time, it's safer to force popper update before showing it. | ||
update?.(); | ||
} | ||
}, [open, update]); | ||
|
||
return { | ||
attributes, | ||
popperElementRef, | ||
styles, | ||
}; | ||
} |