Skip to content

Commit 72b8098

Browse files
devongovettLFDanLu
andauthored
Fix buttons in S2 dialogs stuck in hover state (#6916)
Co-authored-by: Daniel Lu <[email protected]>
1 parent d27e833 commit 72b8098

File tree

1 file changed

+105
-104
lines changed

1 file changed

+105
-104
lines changed

packages/@react-spectrum/s2/src/Dialog.tsx

Lines changed: 105 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {PopoverProps as AriaPopoverProps, composeRenderProps, Provider, Dialog as RACDialog, DialogProps as RACDialogProps} from 'react-aria-components';
13+
import {PopoverProps as AriaPopoverProps, composeRenderProps, OverlayTriggerStateContext, Provider, Dialog as RACDialog, DialogProps as RACDialogProps} from 'react-aria-components';
1414
import {ButtonGroupContext} from './ButtonGroup';
1515
import {CloseButton} from './CloseButton';
1616
import {ContentContext, FooterContext, HeaderContext, HeadingContext, ImageContext} from './Content';
@@ -187,125 +187,126 @@ function DialogInner(props: DialogProps & DialogContextValue & {dialogRef: RefOb
187187
ref={props.dialogRef}
188188
style={props.UNSAFE_style}
189189
className={(props.UNSAFE_className || '') + dialogInner}>
190-
{composeRenderProps(props.children, (children, {close}) =>
191-
// Render the children multiple times inside the wrappers we need to implement the layout.
192-
// Each instance hides certain children so that they are all rendered in the correct locations.
193-
(<>
194-
{/* Hero image */}
195-
<Provider
196-
values={[
197-
[ImageContext, {className: image}],
198-
[HeadingContext, {isHidden: true}],
199-
[HeaderContext, {isHidden: true}],
200-
[ContentContext, {isHidden: true}],
201-
[FooterContext, {isHidden: true}],
202-
[ButtonGroupContext, {isHidden: true}]
203-
]}>
204-
{children}
205-
</Provider>
206-
{/* Top header: heading, header, dismiss button, and button group (in fullscreen dialogs). */}
190+
{composeRenderProps(props.children, (children, {close}) => (
191+
// Render the children multiple times inside the wrappers we need to implement the layout.
192+
// Each instance hides certain children so that they are all rendered in the correct locations.
193+
// Reset OverlayTriggerStateContext so the buttons inside the dialog don't retain their hover state.
194+
<OverlayTriggerStateContext.Provider value={null}>
195+
{/* Hero image */}
196+
<Provider
197+
values={[
198+
[ImageContext, {className: image}],
199+
[HeadingContext, {isHidden: true}],
200+
[HeaderContext, {isHidden: true}],
201+
[ContentContext, {isHidden: true}],
202+
[FooterContext, {isHidden: true}],
203+
[ButtonGroupContext, {isHidden: true}]
204+
]}>
205+
{children}
206+
</Provider>
207+
{/* Top header: heading, header, dismiss button, and button group (in fullscreen dialogs). */}
208+
<div
209+
className={style({
210+
// Wrapper that creates the margin for the dismiss button.
211+
display: 'flex',
212+
alignItems: 'start',
213+
columnGap: 12,
214+
marginStart: {
215+
default: 32
216+
},
217+
marginEnd: {
218+
default: 32,
219+
isDismissable: 12
220+
},
221+
marginTop: {
222+
default: 12 // margin to dismiss button
223+
}
224+
})({isDismissable: props.isDismissable, type: props.type})}>
207225
<div
208226
className={style({
209-
// Wrapper that creates the margin for the dismiss button.
227+
// Wrapper for heading, header, and button group.
228+
// This swaps orientation from horizontal to vertical at small screen sizes.
210229
display: 'flex',
211-
alignItems: 'start',
212-
columnGap: 12,
213-
marginStart: {
214-
default: 32
215-
},
216-
marginEnd: {
217-
default: 32,
218-
isDismissable: 12
219-
},
230+
flexGrow: 1,
220231
marginTop: {
221-
default: 12 // margin to dismiss button
222-
}
223-
})({isDismissable: props.isDismissable, type: props.type})}>
224-
<div
225-
className={style({
226-
// Wrapper for heading, header, and button group.
227-
// This swaps orientation from horizontal to vertical at small screen sizes.
228-
display: 'flex',
229-
flexGrow: 1,
230-
marginTop: {
231-
default: 20, // 32 - 12 (handled above)
232-
':empty': 0
233-
},
234-
marginBottom: {
235-
default: 16,
236-
':empty': 0
237-
},
238-
columnGap: 24,
239-
rowGap: 8,
240-
flexDirection: {
241-
default: 'column',
242-
sm: 'row'
243-
},
244-
alignItems: {
245-
default: 'start',
246-
sm: 'center'
247-
}
248-
})}>
249-
<Provider
250-
values={[
251-
[ImageContext, {hidden: true}],
252-
[HeadingContext, {styles: heading}],
253-
[HeaderContext, {styles: header}],
254-
[ContentContext, {isHidden: true}],
255-
[FooterContext, {isHidden: true}],
256-
[ButtonGroupContext, {isHidden: buttonGroupPlacement !== 'top'}]
257-
]}>
258-
{children}
259-
</Provider>
260-
</div>
261-
{props.isDismissable &&
262-
<CloseButton aria-label={stringFormatter.format('dialog.dismiss')} onPress={close} styles={style({marginBottom: 12})} />
263-
}
264-
</div>
265-
{/* Main content */}
266-
<Provider
267-
values={[
268-
[ImageContext, {hidden: true}],
269-
[HeadingContext, {isHidden: true}],
270-
[HeaderContext, {isHidden: true}],
271-
[ContentContext, {styles: content({type: props.type})}],
272-
[FooterContext, {isHidden: true}],
273-
[ButtonGroupContext, {isHidden: true}]
274-
]}>
275-
{children}
276-
</Provider>
277-
{/* Footer and button group */}
278-
<div
279-
className={style({
280-
display: 'flex',
281-
paddingX: {
282-
default: 32
283-
},
284-
paddingBottom: {
285-
default: 32
232+
default: 20, // 32 - 12 (handled above)
233+
':empty': 0
286234
},
287-
paddingTop: {
288-
default: 32,
235+
marginBottom: {
236+
default: 16,
289237
':empty': 0
290238
},
291-
gap: 24,
292-
alignItems: 'center',
293-
flexWrap: 'wrap'
239+
columnGap: 24,
240+
rowGap: 8,
241+
flexDirection: {
242+
default: 'column',
243+
sm: 'row'
244+
},
245+
alignItems: {
246+
default: 'start',
247+
sm: 'center'
248+
}
294249
})}>
295250
<Provider
296251
values={[
297252
[ImageContext, {hidden: true}],
298-
[HeadingContext, {isHidden: true}],
299-
[HeaderContext, {isHidden: true}],
253+
[HeadingContext, {styles: heading}],
254+
[HeaderContext, {styles: header}],
300255
[ContentContext, {isHidden: true}],
301-
[FooterContext, {styles: footer}],
302-
[ButtonGroupContext, {isHidden: buttonGroupPlacement !== 'bottom', styles: buttonGroup, align: 'end'}]
256+
[FooterContext, {isHidden: true}],
257+
[ButtonGroupContext, {isHidden: buttonGroupPlacement !== 'top'}]
303258
]}>
304259
{children}
305260
</Provider>
306261
</div>
307-
</>)
308-
)}
262+
{props.isDismissable &&
263+
<CloseButton aria-label={stringFormatter.format('dialog.dismiss')} onPress={close} styles={style({marginBottom: 12})} />
264+
}
265+
</div>
266+
{/* Main content */}
267+
<Provider
268+
values={[
269+
[ImageContext, {hidden: true}],
270+
[HeadingContext, {isHidden: true}],
271+
[HeaderContext, {isHidden: true}],
272+
[ContentContext, {styles: content({type: props.type})}],
273+
[FooterContext, {isHidden: true}],
274+
[ButtonGroupContext, {isHidden: true}]
275+
]}>
276+
{children}
277+
</Provider>
278+
{/* Footer and button group */}
279+
<div
280+
className={style({
281+
display: 'flex',
282+
paddingX: {
283+
default: 32
284+
},
285+
paddingBottom: {
286+
default: 32
287+
},
288+
paddingTop: {
289+
default: 32,
290+
':empty': 0
291+
},
292+
gap: 24,
293+
alignItems: 'center',
294+
flexWrap: 'wrap'
295+
})}>
296+
<Provider
297+
values={[
298+
[ImageContext, {hidden: true}],
299+
[HeadingContext, {isHidden: true}],
300+
[HeaderContext, {isHidden: true}],
301+
[ContentContext, {isHidden: true}],
302+
[FooterContext, {styles: footer}],
303+
[ButtonGroupContext, {isHidden: buttonGroupPlacement !== 'bottom', styles: buttonGroup, align: 'end'}]
304+
]}>
305+
{children}
306+
</Provider>
307+
</div>
308+
</OverlayTriggerStateContext.Provider>
309+
))}
309310
</RACDialog>
310311
);
311312
}

0 commit comments

Comments
 (0)