1- import styled from 'styled-components' ;
21import { useDOMRef } from '@react-spectrum/utils' ;
3- import { DismissButton } from 'react-aria' ;
4- import { forwardRef , ReactElement } from 'react' ;
2+ import { DismissButton , FocusScope , useFocusManager } from 'react-aria' ;
3+ import { forwardRef , ReactElement , useEffect , useMemo , useState } from 'react' ;
54import { useDialog , useMessageFormatter , AriaDialogProps } from 'react-aria' ;
65import { DOMRef } from '@react-types/shared' ;
7- import FocusLock from 'react-focus-lock' ;
86
97import {
108 BASE_STYLES ,
@@ -31,35 +29,40 @@ const DialogElement = tasty({
3129 as : 'section' ,
3230 styles : {
3331 pointerEvents : 'auto' ,
34- position : 'relative' ,
32+ position : {
33+ '' : 'relative' ,
34+ '[data-type="panel"]' : 'absolute' ,
35+ } ,
3536 display : 'flex' ,
3637 placeItems : 'stretch' ,
3738 placeContent : 'stretch' ,
3839 width : {
3940 '' : '288px @dialog-size 90vw' ,
4041 '[data-type="fullscreen"]' : '90vw 90vw' ,
4142 '[data-type="fullscreenTakeover"]' : '100vw 100vw' ,
42- '[data-type="panel"]' : '100vw 100vw ' ,
43+ '[data-type="panel"]' : 'auto ' ,
4344 } ,
4445 height : {
4546 '' : 'max 90vh' ,
4647 '[data-type="fullscreenTakeover"] | [data-type="panel"]' : 'max 100vh' ,
48+ '[data-type="panel"]' : 'auto' ,
4749 } ,
4850 gap : 0 ,
4951 flow : 'column' ,
5052 radius : {
5153 '' : '(@large-radius + 1bw)' ,
5254 '[data-type="tray"]' : '(@large-radius + 1bw) top' ,
53- '[data-type="fullscreenTakeover"] | [data-type="panel"] ' : '0r' ,
55+ '[data-type="fullscreenTakeover"]' : '0r' ,
5456 } ,
5557 fill : '#white' ,
5658 shadow : {
57- '' : '0 20px 30px #shadow' ,
58- '[data-type="popover"]' : '0px 4px 16px #shadow' ,
59+ '' : '0 2x 4x #shadow' ,
60+ '[data-type="popover"] | [data-type="panel"] ' : '0px .5x 2x #shadow' ,
5961 } ,
6062 top : {
6163 '' : false ,
6264 '[data-type="modal"]' : '((50vh - 50%) / -3)' ,
65+ '[data-type="panel"]' : 'auto' ,
6366 } ,
6467 placeSelf : 'stretch' ,
6568 '@dialog-heading-padding-v' : {
@@ -82,10 +85,6 @@ const DialogElement = tasty({
8285 } ,
8386} ) ;
8487
85- const StyledFocusLock = styled ( FocusLock ) `
86- display: contents;
87- ` ;
88-
8988const CLOSE_BUTTON_STYLES : Styles = {
9089 display : 'flex' ,
9190 position : 'absolute' ,
@@ -144,10 +143,16 @@ export const Dialog = forwardRef(function Dialog(
144143
145144 const isEntered = transitionContext ?. transitionState === 'entered' ;
146145
146+ const context = useDialogContext ( ) ;
147+
148+ const content = useMemo ( ( ) => {
149+ return < DialogContent key = "content" { ...props } ref = { ref } /> ;
150+ } , [ props , ref ] ) ;
151+
147152 return (
148- < StyledFocusLock returnFocus disabled = { ! isEntered } >
149- < DialogContent key = "content" { ... props } ref = { ref } />
150- </ StyledFocusLock >
153+ < FocusScope restoreFocus contain = { isEntered && context . type !== 'panel' } >
154+ { content }
155+ </ FocusScope >
151156 ) ;
152157} ) ;
153158
@@ -168,6 +173,8 @@ const DialogContent = forwardRef(function DialogContent(
168173 ...otherProps
169174 } = props ;
170175
176+ const [ isCloseDisabled , setIsCloseDisabled ] = useState ( true ) ;
177+
171178 size = sizeMap [ size . toUpperCase ( ) ] || size ;
172179
173180 const styles : Styles = extractStyles ( otherProps , STYLES_LIST ) ;
@@ -187,6 +194,20 @@ const DialogContent = forwardRef(function DialogContent(
187194 dismissButton = < DismissButton onDismiss = { onDismiss } /> ;
188195 }
189196
197+ const focusManager = useFocusManager ( ) ;
198+
199+ // Focus the first focusable element in the dialog when it opens
200+ useEffect ( ( ) => {
201+ if ( contextProps . isOpen ) {
202+ setTimeout ( ( ) => {
203+ focusManager ?. focusFirst ( ) ;
204+ setIsCloseDisabled ( false ) ;
205+ } ) ;
206+ } else {
207+ setIsCloseDisabled ( true ) ;
208+ }
209+ } , [ contextProps . isOpen ] ) ;
210+
190211 // let hasHeader = useHasChild('[data-id="Header"]', domRef);
191212 // let hasFooter = useHasChild('[data-id="Footer"]', domRef);
192213
@@ -241,6 +262,7 @@ const DialogContent = forwardRef(function DialogContent(
241262 styles = { styles }
242263 as = "section"
243264 { ...dialogProps }
265+ tabIndex = { undefined }
244266 mods = { { dismissable : isDismissable } }
245267 style = { { '--dialog-size' : `${ sizePxMap [ size ] || 288 } px` } }
246268 data-type = { type }
@@ -251,6 +273,7 @@ const DialogContent = forwardRef(function DialogContent(
251273 < SlotProvider slots = { slots } >
252274 { isDismissable && (
253275 < Button
276+ isDisabled = { isCloseDisabled }
254277 qa = "ModalCloseButton"
255278 type = "neutral"
256279 styles = { CLOSE_BUTTON_STYLES }
0 commit comments