From 0c4b83a26bee7af2cb4075b3b4738560803c3e18 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 1 Nov 2024 11:29:36 +0100 Subject: [PATCH 1/7] try to repro #4027 --- .../SelectPanel.examples.stories.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx index 3e261c6bce3..3fe70082217 100644 --- a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx @@ -7,6 +7,7 @@ import {SelectPanel} from './SelectPanel' import type {OverlayProps} from '../Overlay' import {TriangleDownIcon} from '@primer/octicons-react' import {ActionList} from '../deprecated/ActionList' +import {Stack} from '../Stack' const meta = { title: 'Components/SelectPanel/Examples', @@ -345,3 +346,37 @@ export const ItemsInScope = () => { ) } + +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 ( + <> + +

Items in component scope

+ +
+ + ) +} From e919c186ab0144fd9fc9041cbb075cadbb63acc7 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 1 Nov 2024 12:00:44 +0100 Subject: [PATCH 2/7] add panel inside dialog --- .../SelectPanel.examples.stories.tsx | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx index 3fe70082217..3c71d8cdeb2 100644 --- a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx @@ -8,6 +8,7 @@ import type {OverlayProps} from '../Overlay' import {TriangleDownIcon} from '@primer/octicons-react' import {ActionList} from '../deprecated/ActionList' import {Stack} from '../Stack' +import {Dialog} from '../experimental' const meta = { title: 'Components/SelectPanel/Examples', @@ -364,7 +365,7 @@ export const RepositionAfterLoading = () => { return ( <> -

Items in component scope

+

Reposition panel after loading

{ ) } + +export const SelectPanelInsideDialog = () => { + 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

+ +
+
+ ) +} From 0f4736abc3873327fda32543021cf9546861cb17 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 1 Nov 2024 12:25:44 +0100 Subject: [PATCH 3/7] add repro in anchored overlay --- .../AnchoredOverlay.features.stories.tsx | 98 ++++++++++++++++++- .../SelectPanel.examples.stories.tsx | 4 +- 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx index 3f914def820..38cf1e3c0ee 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: +

    +
  • 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
+ )} +
+
+ ) +} + +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/SelectPanel/SelectPanel.examples.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx index 3c71d8cdeb2..250f6c66d28 100644 --- a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx @@ -382,7 +382,7 @@ export const RepositionAfterLoading = () => { ) } -export const SelectPanelInsideDialog = () => { +export const SelectPanelRepositionInsideDialog = () => { const [selected, setSelected] = React.useState([items[0], items[1]]) const [open, setOpen] = useState(false) const [filter, setFilter] = React.useState('') @@ -397,7 +397,7 @@ export const SelectPanelInsideDialog = () => { }, [open]) return ( - {}}> + {}}>

other content

Date: Fri, 1 Nov 2024 13:02:02 +0100 Subject: [PATCH 4/7] add resize observer for floating element --- .../AnchoredOverlay/AnchoredOverlay.features.stories.tsx | 8 ++++---- packages/react/src/hooks/useAnchoredPosition.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx index 38cf1e3c0ee..3ceb3678d15 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx @@ -315,14 +315,14 @@ export const RepositionAfterContentGrows = () => { 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
-

+
(
From 784964e34a9ca772fbaebf9810748073a870a2da Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 1 Nov 2024 16:42:50 +0100 Subject: [PATCH 7/7] remove fixes --- packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx | 2 +- packages/react/src/hooks/useAnchoredPosition.ts | 3 +-- packages/react/src/hooks/useResizeObserver.ts | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx index 4924051715e..bfc08cf041a 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx @@ -107,7 +107,7 @@ export const AnchoredOverlay: React.FC) // watches for changes in floating element size + useResizeObserver(updatePosition) return { floatingElementRef, diff --git a/packages/react/src/hooks/useResizeObserver.ts b/packages/react/src/hooks/useResizeObserver.ts index 2a680f55ac6..2fdd18326e9 100644 --- a/packages/react/src/hooks/useResizeObserver.ts +++ b/packages/react/src/hooks/useResizeObserver.ts @@ -16,9 +16,8 @@ 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 } @@ -32,5 +31,5 @@ export function useResizeObserver(callback: ResizeObserve return () => { observer.disconnect() } - }, [targetEl]) + }, [target]) }