2
2
useFoundation ,
3
3
closest ,
4
4
emptyClientRect ,
5
- FoundationElement
5
+ FoundationElement ,
6
+ raf
6
7
} from '@rmwc/base' ;
7
8
import { MenuSurfaceProps , MenuSurfaceApi } from './menu-surface' ;
8
9
@@ -39,7 +40,6 @@ export const useMenuSurfaceFoundation = (
39
40
const firstFocusableElementRef = useRef < HTMLElement | null > ( null ) ;
40
41
const previousFocusRef = useRef < HTMLElement | null > ( null ) ;
41
42
const anchorElementRef = useRef < HTMLElement | null > ( null ) ;
42
- const hoistedRef = useRef ( false ) ;
43
43
44
44
const { foundation, ...elements } = useFoundation ( {
45
45
props,
@@ -52,7 +52,9 @@ export const useMenuSurfaceFoundation = (
52
52
rootEl : FoundationElement < any , any > ;
53
53
} ) : MenuSurfaceApi => {
54
54
return {
55
- hoistMenuToBody : ( ) => hoistMenuToBody ( ) ,
55
+ hoistMenuToBody : ( ) => {
56
+ // this is controlled by the renderToPortal prop
57
+ } ,
56
58
setAnchorCorner : ( corner : Corner ) => foundation . setAnchorCorner ( corner ) ,
57
59
setAnchorElement : ( element : HTMLElement ) =>
58
60
( anchorElementRef . current = element ) ,
@@ -233,32 +235,6 @@ export const useMenuSurfaceFoundation = (
233
235
234
236
rootEl . setProp ( 'onKeyDown' , handleKeydown , true ) ;
235
237
236
- const hoistMenuToBody = useCallback ( ( ) => {
237
- if ( rootEl . ref ?. parentElement ) {
238
- document . body . appendChild (
239
- rootEl . ref . parentElement . removeChild ( rootEl . ref )
240
- ) ;
241
- hoistedRef . current = true ;
242
- foundation . setIsHoisted ( true ) ;
243
-
244
- // correct layout for open menu
245
- if ( foundation . isOpen ( ) ) {
246
- // wait an extra frame so that the element is actually
247
- // done being hoisted and painting. Fixes Issue #453
248
- // @ts -ignore unsafe private variable access
249
- window . requestAnimationFrame ( ( ) => foundation . autoPosition_ ( ) ) ;
250
- }
251
- }
252
- } , [ foundation , rootEl . ref ] ) ;
253
-
254
- const unhoistMenuFromBody = useCallback ( ( ) => {
255
- if ( anchorElementRef . current && rootEl . ref ) {
256
- anchorElementRef . current . appendChild ( rootEl . ref ) ;
257
- hoistedRef . current = false ;
258
- foundation . setIsHoisted ( false ) ;
259
- }
260
- } , [ foundation , rootEl . ref ] ) ;
261
-
262
238
// fixed
263
239
useEffect ( ( ) => {
264
240
foundation . setFixedPosition ( ! ! props . fixed ) ;
@@ -277,12 +253,34 @@ export const useMenuSurfaceFoundation = (
277
253
}
278
254
} , [ rootEl . ref ] ) ;
279
255
280
- // hoistToBody
256
+ // renderToPortal
281
257
useEffect ( ( ) => {
282
- if ( props . hoistToBody !== undefined ) {
283
- props . hoistToBody ? hoistMenuToBody ( ) : unhoistMenuFromBody ( ) ;
284
- }
285
- } , [ props . hoistToBody , foundation , hoistMenuToBody , unhoistMenuFromBody ] ) ;
258
+ props . renderToPortal
259
+ ? foundation . setIsHoisted ( true )
260
+ : foundation . setIsHoisted ( false ) ;
261
+
262
+ const autoPosition = ( ) => {
263
+ try {
264
+ // silence this, it blows up loudly occasionally
265
+ // @ts -ignore unsafe private variable access
266
+ foundation . autoPosition_ ( ) ;
267
+ } catch ( err ) { }
268
+ } ;
269
+
270
+ // wait an extra frame so that the element is actually
271
+ // done being hoisted and painting. Fixes Issue #453
272
+ const handler = props . renderToPortal ? autoPosition : ( ) => { } ;
273
+
274
+ raf ( ( ) => {
275
+ foundation . isOpen ( ) && autoPosition ( ) ;
276
+ } ) ;
277
+
278
+ // fix positioning on window resize when renderToPortal is true
279
+ window . addEventListener ( 'resize' , handler ) ;
280
+ return ( ) => {
281
+ window . removeEventListener ( 'resize' , handler ) ;
282
+ } ;
283
+ } , [ props . renderToPortal , foundation ] ) ;
286
284
287
285
// anchorCorner
288
286
useEffect ( ( ) => {
@@ -315,28 +313,17 @@ export const useMenuSurfaceFoundation = (
315
313
// changing the open prop externally, while also not
316
314
// conflicting with any internal events that might have closed
317
315
// the menu, like a body click or escape key
318
- window . requestAnimationFrame ( ( ) => {
319
- window . requestAnimationFrame ( ( ) => {
320
- if ( foundation . isOpen ( ) ) {
321
- foundation . close ( ) ;
322
- }
323
- } ) ;
324
- } ) ;
316
+ raf ( ( ) => {
317
+ if ( foundation . isOpen ( ) ) {
318
+ foundation . close ( ) ;
319
+ }
320
+ } , 2 ) ;
325
321
}
326
322
} , [ open , foundation , rootEl . ref ] ) ;
327
323
328
324
useEffect ( ( ) => {
329
325
setOpen ( ! ! props . open ) ;
330
326
} , [ props . open ] ) ;
331
327
332
- useEffect ( ( ) => {
333
- return ( ) => {
334
- // @ts -ignore Fixes unsafe access from MDC when component unmounts
335
- foundation . adapter_ . notifyClose = ( ) => { } ;
336
- unhoistMenuFromBody ( ) ;
337
- } ;
338
- // eslint-disable-next-line react-hooks/exhaustive-deps
339
- } , [ ] ) ;
340
-
341
328
return { ...elements } ;
342
329
} ;
0 commit comments