@@ -39,7 +39,6 @@ import {
3939 useResponsiveMode ,
4040 ZIndexes
4141} from '@fluentui/react' ;
42- import { useWindow } from '@fluentui/react-window-provider' ;
4342
4443// @TODO - need to change this to a panel whenever the breakpoint is under medium (verify the spec)
4544
@@ -48,6 +47,13 @@ export interface _ExtendedIModalProps extends IModalProps {
4847 minDragPosition ?: _ICoordinates ;
4948 maxDragPosition ?: _ICoordinates ;
5049 dataUiId ?: string ;
50+
51+ /**
52+ * Originally the FluentUI modal used window to capture key events that trigger the move/close menu.
53+ * As we want to avoid global listeners, we are allowing the user to pass in a specific element
54+ * to capture the key events.
55+ */
56+ keyEventElement ?: HTMLElement | Window ;
5157}
5258
5359const animationDuration = AnimationVariables . durationValue2 ;
@@ -84,7 +90,7 @@ const DEFAULT_PROPS: Partial<_ExtendedIModalProps> = {
8490
8591const getModalClassNames = classNamesFunction < IModalStyleProps , IModalStyles > ( ) ;
8692
87- const getMoveDelta = ( ev : React . KeyboardEvent < HTMLElement > ) : number => {
93+ const getMoveDelta = ( ev : KeyboardEvent ) : number => {
8894 let delta = 10 ;
8995 if ( ev . shiftKey ) {
9096 if ( ! ev . ctrlKey ) {
@@ -144,7 +150,8 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
144150 onDismissed,
145151 minDragPosition,
146152 maxDragPosition,
147- dataUiId
153+ dataUiId,
154+ keyEventElement = window
148155 } = props ;
149156
150157 const rootRef = React . useRef < HTMLDivElement > ( null ) ;
@@ -156,16 +163,17 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
156163
157164 const focusTrapZoneId = useId ( 'ModalFocusTrapZone' ) ;
158165
159- const win = useWindow ( ) ;
160-
161166 const { setTimeout, clearTimeout } = useSetTimeout ( ) ;
162167
163168 const [ isModalOpen , setIsModalOpen ] = React . useState ( isOpen ) ;
164169 const [ isVisible , setIsVisible ] = React . useState ( isOpen ) ;
165170 const [ coordinates , setCoordinates ] = React . useState < _ICoordinates > ( ZERO ) ;
166171 const [ modalRectangleTop , setModalRectangleTop ] = React . useState < number | undefined > ( ) ;
167172
168- const [ isModalMenuOpen , { toggle : toggleModalMenuOpen , setFalse : setModalMenuClose } ] = useBoolean ( false ) ;
173+ const [ isModalMenuOpen , { setTrue : setModalMenuOpen , setFalse : setModalMenuClose } ] = useBoolean ( false ) ;
174+
175+ const [ _ , forceUpdate ] = React . useState ( 0 ) ;
176+ const forceUpdateCallback = React . useCallback ( ( ) => forceUpdate ( ( prev ) => prev + 1 ) , [ ] ) ;
169177
170178 const internalState = useConst < IModalInternalState > ( ( ) => ( {
171179 onModalCloseTimer : 0 ,
@@ -192,7 +200,7 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
192200 topOffsetFixed,
193201 isModeless,
194202 layerClassName,
195- windowInnerHeight : win ?. innerHeight ,
203+ windowInnerHeight : window ?. innerHeight ,
196204 isDefaultDragHandle : dragOptions && ! dragOptions . dragHandleSelector
197205 } ) ;
198206
@@ -300,7 +308,8 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
300308 const handleEnterKeyboardMoveMode = ( ) => {
301309 // We need a global handleKeyDown event when we are in the move mode so that we can
302310 // handle the key presses and the components inside the modal do not get the events
303- const handleKeyDown = ( ev : React . KeyboardEvent < HTMLElement > ) : void => {
311+ const handleKeyDown = ( event : Event ) : void => {
312+ const ev = event as KeyboardEvent ;
304313 if ( ev . altKey && ev . ctrlKey && ev . keyCode === KeyCodes . space ) {
305314 // CTRL + ALT + SPACE is handled during keyUp
306315 ev . preventDefault ( ) ;
@@ -315,6 +324,7 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
315324
316325 if ( internalState . isInKeyboardMoveMode && ( ev . keyCode === KeyCodes . escape || ev . keyCode === KeyCodes . enter ) ) {
317326 internalState . isInKeyboardMoveMode = false ;
327+ forceUpdateCallback ( ) ;
318328 ev . preventDefault ( ) ;
319329 ev . stopPropagation ( ) ;
320330 }
@@ -364,10 +374,9 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
364374 internalState . lastSetCoordinates = coordinates ;
365375 setModalMenuClose ( ) ;
366376 internalState . isInKeyboardMoveMode = true ;
367-
368- internalState . events . on ( win , 'keydown' , handleKeyDown , true /* useCapture */ ) ;
377+ keyEventElement . addEventListener ( 'keydown' , handleKeyDown , true /* useCapture */ ) ;
369378 internalState . disposeOnKeyDown = ( ) => {
370- internalState . events . off ( win , 'keydown' , handleKeyDown , true /* useCapture */ ) ;
379+ keyEventElement . removeEventListener ( 'keydown' , handleKeyDown , true /* useCapture */ ) ;
371380 internalState . disposeOnKeyDown = undefined ;
372381 } ;
373382 } ;
@@ -379,22 +388,23 @@ const ModalBase: React.FunctionComponent<_ExtendedIModalProps> = React.forwardRe
379388 } ;
380389
381390 const registerForKeyUp = ( ) : void => {
382- const handleKeyUp = ( ev : React . KeyboardEvent < HTMLElement > ) : void => {
391+ const handleKeyUp = ( event : Event ) : void => {
392+ const ev = event as KeyboardEvent ;
383393 // Needs to handle the CTRL + ALT + SPACE key during keyup due to FireFox bug:
384394 // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
385395 if ( ev . altKey && ev . ctrlKey && ev . keyCode === KeyCodes . space ) {
386396 if ( elementContains ( internalState . scrollableContent , ev . target as HTMLElement ) ) {
387- toggleModalMenuOpen ( ) ;
397+ setModalMenuOpen ( ) ;
388398 ev . preventDefault ( ) ;
389399 ev . stopPropagation ( ) ;
390400 }
391401 }
392402 } ;
393403
394404 if ( ! internalState . disposeOnKeyUp ) {
395- internalState . events . on ( win , 'keyup' , handleKeyUp , true /* useCapture */ ) ;
405+ keyEventElement . addEventListener ( 'keyup' , handleKeyUp , true /* useCapture */ ) ;
396406 internalState . disposeOnKeyUp = ( ) => {
397- internalState . events . off ( win , 'keyup' , handleKeyUp , true /* useCapture */ ) ;
407+ keyEventElement . removeEventListener ( 'keyup' , handleKeyUp , true /* useCapture */ ) ;
398408 internalState . disposeOnKeyUp = undefined ;
399409 } ;
400410 }
0 commit comments