diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx index 3f914def820..3ceb3678d15 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useRef, useState} from 'react' import type {Args, Meta} from '@storybook/react' import {FocusKeys} from '@primer/behaviors' -import {Avatar, Box, Link, Text} from '..' +import {Avatar, Box, Dialog, Link, Spinner, Text} from '..' import {AnchoredOverlay} from '../AnchoredOverlay' import Heading from '../Heading' import Octicon from '../Octicon' @@ -301,3 +301,99 @@ export const OverlayPropsOverrides = () => { ) } + +export const RepositionAfterContentGrows = () => { + const [open, setOpen] = useState(false) + + const [loading, setLoading] = useState(true) + + React.useEffect(() => { + window.setTimeout(() => { + if (open) setLoading(false) + }, 2000) + }, [open]) + + return ( + +
+ What to expect: + +
+ ( + + )} + open={open} + onOpen={() => setOpen(true)} + onClose={() => { + setOpen(false) + setLoading(true) + }} + > + {loading ? ( + <> + + loading for 2000ms + + ) : ( +
content with 300px height
+ )} +
+
+ ) +} + +export const RepositionAfterContentGrowsWithinDialog = () => { + const [open, setOpen] = useState(false) + + const [loading, setLoading] = useState(true) + + React.useEffect(() => { + window.setTimeout(() => { + if (open) setLoading(false) + }, 2000) + }, [open]) + + return ( + {}}> + +
+ What to expect: +
    +
  • The anchored overlay should open below the anchor (default position)
  • +
  • After 2000ms, the amount of content in the overlay grows
  • +
  • the overlay should reposition itself above the anchor so that it stays inside the window
  • +
+
+ ( + + )} + open={open} + onOpen={() => setOpen(true)} + onClose={() => { + setOpen(false) + setLoading(true) + }} + > + {loading ? ( + <> + + loading for 2000ms + + ) : ( +
content with 300px height
+ )} +
+
+
+ ) +} diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx index bfc08cf041a..4924051715e 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx @@ -107,7 +107,7 @@ export const AnchoredOverlay: React.FC { ) } + +export const RepositionAfterLoading = () => { + const [selected, setSelected] = React.useState([items[0], items[1]]) + const [open, setOpen] = useState(false) + const [filter, setFilter] = React.useState('') + const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) + const [loading, setLoading] = useState(true) + + React.useEffect(() => { + if (!open) setLoading(true) + window.setTimeout(() => { + if (open) setLoading(false) + }, 2000) + }, [open]) + + return ( + <> + +

Reposition panel after loading

+ +
+ + ) +} + +export const SelectPanelRepositionInsideDialog = () => { + const [selected, setSelected] = React.useState([items[0], items[1]]) + const [open, setOpen] = useState(false) + const [filter, setFilter] = React.useState('') + const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) + const [loading, setLoading] = useState(true) + + React.useEffect(() => { + if (!open) setLoading(true) + window.setTimeout(() => { + if (open) setLoading(false) + }, 2000) + }, [open]) + + return ( + {}}> + +

other content

+ +
+
+ ) +} diff --git a/packages/react/src/hooks/useAnchoredPosition.ts b/packages/react/src/hooks/useAnchoredPosition.ts index 6365a23cd27..60d28472136 100644 --- a/packages/react/src/hooks/useAnchoredPosition.ts +++ b/packages/react/src/hooks/useAnchoredPosition.ts @@ -45,7 +45,8 @@ export function useAnchoredPosition( useLayoutEffect(updatePosition, [updatePosition]) - useResizeObserver(updatePosition) + useResizeObserver(updatePosition) // watches for changes in window size + useResizeObserver(updatePosition, floatingElementRef as React.RefObject) // watches for changes in floating element size return { floatingElementRef, diff --git a/packages/react/src/hooks/useResizeObserver.ts b/packages/react/src/hooks/useResizeObserver.ts index 2fdd18326e9..2a680f55ac6 100644 --- a/packages/react/src/hooks/useResizeObserver.ts +++ b/packages/react/src/hooks/useResizeObserver.ts @@ -16,8 +16,9 @@ export function useResizeObserver(callback: ResizeObserve savedCallback.current = callback }) + const targetEl = target && 'current' in target ? target.current : document.documentElement + useLayoutEffect(() => { - const targetEl = target && 'current' in target ? target.current : document.documentElement if (!targetEl) { return } @@ -31,5 +32,5 @@ export function useResizeObserver(callback: ResizeObserve return () => { observer.disconnect() } - }, [target]) + }, [targetEl]) }