Skip to content

Commit d0bc984

Browse files
authored
add ResizeObserver that observes targetRef (#6396)
add ResizeObserver that observes targetRef
1 parent 369c0f5 commit d0bc984

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

packages/@react-aria/overlays/src/useOverlayPosition.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ export function useOverlayPosition(props: AriaPositionProps): PositionAria {
192192
onResize: updatePosition
193193
});
194194

195+
// Update position when the target changes size (might need to flip).
196+
useResizeObserver({
197+
ref: targetRef,
198+
onResize: updatePosition
199+
});
200+
195201
// Reposition the overlay and do not close on scroll while the visual viewport is resizing.
196202
// This will ensure that overlays adjust their positioning when the iOS virtual keyboard appears.
197203
let isResizing = useRef(false);

packages/react-aria-components/stories/Popover.stories.tsx

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import {Button, Dialog, DialogTrigger, Heading, OverlayArrow, Popover} from 'react-aria-components';
14-
import React from 'react';
14+
import React, {useEffect, useRef, useState} from 'react';
1515

1616
export default {
1717
title: 'React Aria Components'
@@ -49,6 +49,79 @@ export const PopoverExample = () => (
4949
</DialogTrigger>
5050
);
5151

52+
53+
const COUNTDOWN = 5000;
54+
55+
function PopoverTriggerObserver() {
56+
const buttonRef = useRef<HTMLButtonElement>(null);
57+
const [countdown, setCountdown] = useState(COUNTDOWN);
58+
59+
useEffect(() => {
60+
if (countdown > 0) {
61+
const intervalId = setInterval(() => {
62+
setCountdown(countdown - 1000);
63+
}, 1000);
64+
return () => {
65+
clearInterval(intervalId);
66+
};
67+
}
68+
}, [countdown]);
69+
70+
useEffect(() => {
71+
const timeoutId = setTimeout(() => {
72+
if (buttonRef.current) {
73+
buttonRef.current.style.width = '200px';
74+
buttonRef.current.style.height = '50px';
75+
}
76+
}, COUNTDOWN + 1000);
77+
return () => {
78+
clearTimeout(timeoutId);
79+
};
80+
}, []);
81+
82+
return (
83+
<div style={{marginBottom: 100, display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
84+
<div>
85+
<p>The trigger button below will change size in <strong>{Math.floor(countdown / 1000)}s</strong></p>
86+
</div>
87+
<DialogTrigger defaultOpen>
88+
<Button ref={buttonRef}>Open popover</Button>
89+
<Popover
90+
placement="bottom start"
91+
style={{
92+
background: 'Canvas',
93+
color: 'CanvasText',
94+
border: '1px solid gray',
95+
padding: 30,
96+
zIndex: 5
97+
}}>
98+
<Dialog>
99+
{({close}) => (
100+
<form style={{display: 'flex', flexDirection: 'column'}}>
101+
<Heading slot="title">Sign up</Heading>
102+
<label>
103+
First Name: <input placeholder="John" />
104+
</label>
105+
<label>
106+
Last Name: <input placeholder="Smith" />
107+
</label>
108+
<Button onPress={close} style={{marginTop: 10}}>
109+
Submit
110+
</Button>
111+
</form>
112+
)}
113+
</Dialog>
114+
</Popover>
115+
</DialogTrigger>
116+
</div>
117+
);
118+
}
119+
120+
121+
export const PopoverTriggerObserverExample = {
122+
render: PopoverTriggerObserver
123+
};
124+
52125
export const PopoverArrowBoundaryOffsetExample = {
53126
args: {
54127
topLeft: 25,

0 commit comments

Comments
 (0)