7
7
import '../../elevation/elevation.js' ;
8
8
import '../../focus/md-focus-ring.js' ;
9
9
10
- import { html , isServer , LitElement , PropertyValues } from 'lit' ;
10
+ import { LitElement , PropertyValues , html , isServer , nothing } from 'lit' ;
11
11
import { property , query , queryAssignedElements , state } from 'lit/decorators.js' ;
12
12
import { ClassInfo , classMap } from 'lit/directives/class-map.js' ;
13
13
import { styleMap } from 'lit/directives/style-map.js' ;
@@ -16,7 +16,7 @@ import {
16
16
polyfillARIAMixin ,
17
17
polyfillElementInternalsAria ,
18
18
} from '../../internal/aria/aria.js' ;
19
- import { createAnimationSignal , EASING } from '../../internal/motion/animation.js' ;
19
+ import { EASING , createAnimationSignal } from '../../internal/motion/animation.js' ;
20
20
import {
21
21
ListController ,
22
22
NavigableKeys ,
@@ -107,9 +107,12 @@ export abstract class Menu extends LitElement {
107
107
@property ( ) anchor = '' ;
108
108
/**
109
109
* Whether the positioning algorithim should calculate relative to the parent
110
- * of the anchor element (absolute) or relative to the window (fixed).
110
+ * of the anchor element (`absolute`), relative to the window (`fixed`), or
111
+ * relative to the document (`document`). `popover` will use the popover API
112
+ * to render the menu in the top-layer. If your browser does not support the
113
+ * popover API, it will revert to `fixed`.
111
114
*
112
- * Examples for `position = 'fixed'`:
115
+ * __Examples for `position = 'fixed'`:__
113
116
*
114
117
* - If there is no `position:relative` in the given parent tree and the
115
118
* surface is `position:absolute`
@@ -118,7 +121,7 @@ export abstract class Menu extends LitElement {
118
121
* - The anchor and the surface do not share a common `position:relative`
119
122
* ancestor
120
123
*
121
- * When using positioning = fixed, in most cases, the menu should position
124
+ * When using ` positioning= fixed` , in most cases, the menu should position
122
125
* itself above most other `position:absolute` or `position:fixed` elements
123
126
* when placed inside of them. e.g. using a menu inside of an `md-dialog`.
124
127
*
@@ -134,8 +137,14 @@ export abstract class Menu extends LitElement {
134
137
* end of the `<body>` to render over everything or in a top-layer.
135
138
* - You are reusing a single `md-menu` element that dynamically renders
136
139
* content.
140
+ *
141
+ * __Examples for `position = 'popover'`:__
142
+ *
143
+ * - Your browser supports `popover`.
144
+ * - Most cases. Once popover is in browsers, this will become the default.
137
145
*/
138
- @property ( ) positioning : 'absolute' | 'fixed' | 'document' = 'absolute' ;
146
+ @property ( ) positioning : 'absolute' | 'fixed' | 'document' | 'popover' =
147
+ 'absolute' ;
139
148
/**
140
149
* Skips the opening and closing animations.
141
150
*/
@@ -362,7 +371,8 @@ export abstract class Menu extends LitElement {
362
371
surfaceCorner : this . menuCorner ,
363
372
surfaceEl : this . surfaceEl ,
364
373
anchorEl : this . anchorElement ,
365
- positioning : this . positioning ,
374
+ positioning :
375
+ this . positioning === 'popover' ? 'document' : this . positioning ,
366
376
isOpen : this . open ,
367
377
xOffset : this . xOffset ,
368
378
yOffset : this . yOffset ,
@@ -372,7 +382,10 @@ export abstract class Menu extends LitElement {
372
382
// We can't resize components that have overflow like menus with
373
383
// submenus because the overflow-y will show menu items / content
374
384
// outside the bounds of the menu. (to be fixed w/ popover API)
375
- repositionStrategy : this . hasOverflow ? 'move' : 'resize' ,
385
+ repositionStrategy :
386
+ this . hasOverflow && this . positioning !== 'popover'
387
+ ? 'move'
388
+ : 'resize' ,
376
389
} ;
377
390
} ,
378
391
) ;
@@ -407,13 +420,25 @@ export abstract class Menu extends LitElement {
407
420
}
408
421
}
409
422
423
+ // Firefox does not support popover. Fall-back to using fixed.
424
+ if (
425
+ changed . has ( 'positioning' ) &&
426
+ this . positioning === 'popover' &&
427
+ // type required for Google JS conformance
428
+ ! ( this as unknown as { showPopover ?: ( ) => void } ) . showPopover
429
+ ) {
430
+ this . positioning = 'fixed' ;
431
+ }
432
+
410
433
super . update ( changed ) ;
411
434
}
412
435
413
436
private readonly onWindowResize = ( ) => {
414
437
if (
415
438
this . isRepositioning ||
416
- ( this . positioning !== 'document' && this . positioning !== 'fixed' )
439
+ ( this . positioning !== 'document' &&
440
+ this . positioning !== 'fixed' &&
441
+ this . positioning !== 'popover' )
417
442
) {
418
443
return ;
419
444
}
@@ -445,7 +470,8 @@ export abstract class Menu extends LitElement {
445
470
return html `
446
471
< div
447
472
class ="menu ${ classMap ( this . getSurfaceClasses ( ) ) } "
448
- style =${ styleMap ( this . menuPositionController . surfaceStyles ) } >
473
+ style =${ styleMap ( this . menuPositionController . surfaceStyles ) }
474
+ popover =${ this . positioning === 'popover' ? 'manual' : nothing } >
449
475
${ this . renderElevation ( ) }
450
476
< div class ="items ">
451
477
< div class ="item-padding "> ${ this . renderMenuItems ( ) } </ div >
0 commit comments