diff --git a/docs/content/Overlay.mdx b/docs/content/Overlay.mdx
index fc97fff6c14..34e4e8ba9fa 100644
--- a/docs/content/Overlay.mdx
+++ b/docs/content/Overlay.mdx
@@ -77,3 +77,4 @@ render()
| onEscape | `function` | `undefined` | Required. Function to call when user presses `Escape`. Typically this function sets the `Overlay` visibility state to `false`. |
| width | `'sm', 'md', 'lg', 'xl', 'auto'` | `auto` | Sets the width of the `Overlay`, pick from our set list of widths, or pass `auto` to automatically set the width based on the content of the `Overlay`. `sm` corresponds to `256px`, `md` corresponds to `320px`, `lg` corresponds to `480px`, and `xl` corresponds to `640px`. |
| height | `'sm', 'md', 'auto'` | `auto` | Sets the height of the `Overlay`, pick from our set list of heights, or pass `auto` to automatically set the height based on the content of the `Overlay`. `sm` corresponds to `480px` and `md` corresponds to `640px`. |
+| visibility | `'visible', 'hidden'` | `visible` | Sets the visibility of the `Overlay`. |
diff --git a/src/ActionMenu.tsx b/src/ActionMenu.tsx
index 88b4b3066c8..3b77bb77889 100644
--- a/src/ActionMenu.tsx
+++ b/src/ActionMenu.tsx
@@ -75,7 +75,13 @@ const ActionMenuBase = ({
[open]
)
- const {position} = useAnchoredPosition({anchorElementRef: anchorRef, floatingElementRef: overlayRef})
+ const {position} = useAnchoredPosition(
+ {
+ anchorElementRef: anchorRef,
+ floatingElementRef: overlayRef
+ },
+ [overlayRef.current]
+ )
useFocusZone({containerRef: overlayRef, disabled: !open || state !== 'listFocus'}, [position])
useFocusTrap({containerRef: overlayRef, disabled: !open || state !== 'listFocus'}, [position])
@@ -100,6 +106,7 @@ const ActionMenuBase = ({
onClickOutside={onDismiss}
onEscape={onDismiss}
ref={updateOverlayRef}
+ visibility={position ? 'visible' : 'hidden'}
{...position}
>
diff --git a/src/Overlay.tsx b/src/Overlay.tsx
index 3eb50a7154e..fa88c725153 100644
--- a/src/Overlay.tsx
+++ b/src/Overlay.tsx
@@ -10,6 +10,7 @@ import {useCombinedRefs} from './hooks/useCombinedRefs'
type StyledOverlayProps = {
width?: keyof typeof widthMap
height?: keyof typeof heightMap
+ visibility?: 'visible' | 'hidden'
}
const heightMap = {
@@ -48,6 +49,7 @@ const StyledOverlay = styled.div props.visibility || 'visible'};
${COMMON};
${POSITION};
${sx};
@@ -58,7 +60,8 @@ export type OverlayProps = {
returnFocusRef: React.RefObject
onClickOutside: (e: TouchOrMouseEvent) => void
onEscape: (e: KeyboardEvent) => void
-} & Omit, keyof SystemPositionProps>
+ visibility?: 'visible' | 'hidden'
+} & Omit, 'visibility' | keyof SystemPositionProps>
/**
* An `Overlay` is a flexible floating surface, used to display transient content such as menus,
@@ -71,10 +74,11 @@ export type OverlayProps = {
* @param onEscape Required. Function to call when user presses `Escape`. Typically this function sets the `Overlay` visibility state to `false`.
* @param width Sets the width of the `Overlay`, pick from our set list of widths, or pass `auto` to automatically set the width based on the content of the `Overlay`. `sm` corresponds to `256px`, `md` corresponds to `320px`, `lg` corresponds to `480px`, and `xl` corresponds to `640px`.
* @param height Sets the height of the `Overlay`, pick from our set list of heights, or pass `auto` to automatically set the height based on the content of the `Overlay`. `sm` corresponds to `480px` and `md` corresponds to `640px`.
+ * @param visibility Sets the visibility of the `Overlay`
*/
const Overlay = React.forwardRef(
(
- {onClickOutside, role = 'dialog', initialFocusRef, returnFocusRef, ignoreClickRefs, onEscape, ...rest},
+ {onClickOutside, role = 'dialog', initialFocusRef, returnFocusRef, ignoreClickRefs, onEscape, visibility, ...rest},
forwardedRef
): ReactElement => {
const overlayRef = useRef(null)
@@ -90,7 +94,14 @@ const Overlay = React.forwardRef(
})
return (
-
+
)
}
diff --git a/src/hooks/useAnchoredPosition.ts b/src/hooks/useAnchoredPosition.ts
index 1e5f6e6be43..7ba0a40a4fb 100644
--- a/src/hooks/useAnchoredPosition.ts
+++ b/src/hooks/useAnchoredPosition.ts
@@ -34,7 +34,7 @@ export function useAnchoredPosition(
setPosition(undefined)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [floatingElementRef.current, anchorElementRef.current, ...dependencies])
+ }, [floatingElementRef, anchorElementRef, ...dependencies])
return {
floatingElementRef,
anchorElementRef,
diff --git a/src/hooks/useCombinedRefs.ts b/src/hooks/useCombinedRefs.ts
index c5915b152c2..0fef707de7d 100644
--- a/src/hooks/useCombinedRefs.ts
+++ b/src/hooks/useCombinedRefs.ts
@@ -12,16 +12,27 @@ export function useCombinedRefs(...refs: (ForwardedRef | null | undefined)
const combinedRef = useRef(null)
React.useEffect(() => {
- for (const ref of refs) {
- if (!ref) {
- return
- }
- if (typeof ref === 'function') {
- ref(combinedRef.current ?? null)
- } else {
- ref.current = combinedRef.current ?? null
+ function setRefs(current: T | null = null) {
+ for (const ref of refs) {
+ if (!ref) {
+ return
+ }
+ if (typeof ref === 'function') {
+ ref(current)
+ } else {
+ ref.current = current
+ }
}
}
+
+ setRefs(combinedRef.current)
+
+ return () => {
+ // ensure the refs get updated on unmount
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ setRefs(combinedRef.current)
+ }
+
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...refs, combinedRef.current])