@@ -27,7 +27,7 @@ import pickerStyles from './picker.css.js';
2727import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js' ;
2828
2929import { Focusable } from '@spectrum-web-components/shared/src/focusable.js' ;
30- import reparentChildren from '@spectrum-web-components/shared/src/reparent-children.js' ;
30+ import { reparentChildren } from '@spectrum-web-components/shared/src/reparent-children.js' ;
3131import '@spectrum-web-components/icon/sp-icon.js' ;
3232import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js' ;
3333import '@spectrum-web-components/menu/sp-menu.js' ;
@@ -38,6 +38,7 @@ import {
3838 MenuQueryRoleEventDetail ,
3939} from '@spectrum-web-components/menu' ;
4040import '@spectrum-web-components/popover/sp-popover.js' ;
41+ import { Popover } from '@spectrum-web-components/popover/src/popover.js' ;
4142import {
4243 Placement ,
4344 openOverlay ,
@@ -94,9 +95,10 @@ export class PickerBase extends SizedMixin(Focusable) {
9495 @property ( { type : Boolean , reflect : true } )
9596 public open = false ;
9697
97- private reparentableChildren ?: Element [ ] ;
98+ public menuItems : MenuItem [ ] = [ ] ;
9899 private restoreChildren ?: Function ;
99- public optionsMenu ?: Menu ;
100+
101+ public optionsMenu ! : Menu ;
100102
101103 /**
102104 * @type {"auto" | "auto-start" | "auto-end" | "top" | "bottom" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end" | "none" }
@@ -118,7 +120,7 @@ export class PickerBase extends SizedMixin(Focusable) {
118120 private closeOverlay ?: ( ) => void ;
119121
120122 @query ( 'sp-popover' )
121- private popover ?: HTMLElement ;
123+ private popover ! : Popover ;
122124
123125 protected listRole = 'listbox' ;
124126 protected itemRole = 'option' ;
@@ -144,7 +146,7 @@ export class PickerBase extends SizedMixin(Focusable) {
144146 }
145147
146148 public get focusElement ( ) : HTMLElement {
147- if ( this . open && this . optionsMenu ) {
149+ if ( this . open ) {
148150 return this . optionsMenu ;
149151 }
150152 return this . button ;
@@ -192,10 +194,6 @@ export class PickerBase extends SizedMixin(Focusable) {
192194 return ;
193195 }
194196 event . preventDefault ( ) ;
195- /* c8 ignore next 3 */
196- if ( ! this . optionsMenu ) {
197- return ;
198- }
199197 this . open = true ;
200198 } ;
201199
@@ -243,18 +241,26 @@ export class PickerBase extends SizedMixin(Focusable) {
243241
244242 private async openMenu ( ) : Promise < void > {
245243 /* c8 ignore next 9 */
246- if (
247- ! this . popover ||
248- ! this . optionsMenu ||
249- ! this . reparentableChildren ||
250- this . reparentableChildren . length === 0
251- ) {
244+ let reparentableChildren : Element [ ] = [ ] ;
245+
246+ const deprecatedMenu = this . querySelector ( 'sp-menu' ) ;
247+ if ( deprecatedMenu ) {
248+ reparentableChildren = Array . from ( deprecatedMenu . children ) ;
249+ } else {
250+ reparentableChildren = Array . from ( this . children ) . filter (
251+ ( element ) => {
252+ return ! element . hasAttribute ( 'slot' ) ;
253+ }
254+ ) ;
255+ }
256+
257+ if ( reparentableChildren . length === 0 ) {
252258 this . menuStateResolver ( ) ;
253259 return ;
254260 }
255261
256262 this . restoreChildren = reparentChildren (
257- this . reparentableChildren ,
263+ reparentableChildren ,
258264 this . optionsMenu
259265 ) ;
260266
@@ -331,21 +337,27 @@ export class PickerBase extends SizedMixin(Focusable) {
331337
332338 protected render ( ) : TemplateResult {
333339 return html `
334- ${ this . renderButton }
340+ ${ this . renderButton } ${ this . renderPopover }
341+ ` ;
342+ }
343+
344+ protected get renderPopover ( ) : TemplateResult {
345+ return html `
335346 < sp-popover
336347 open
337348 id ="popover "
338349 @click =${ this . onClick }
339350 @sp-overlay-closed =${ this . onOverlayClosed }
340351 >
341- < sp-menu id ="menu " role ="listbox "> </ sp-menu >
352+ < sp-menu id ="menu " role ="${ this . listRole } "> </ sp-menu >
342353 </ sp-popover >
343354 ` ;
344355 }
345356
346357 protected firstUpdated ( changedProperties : PropertyValues ) : void {
347358 super . firstUpdated ( changedProperties ) ;
348359
360+ // Since the sp-menu gets reparented by the popover, initialize it here
349361 this . optionsMenu = this . shadowRoot . querySelector ( 'sp-menu' ) as Menu ;
350362
351363 const deprecatedMenu = this . querySelector ( 'sp-menu' ) ;
@@ -354,18 +366,14 @@ export class PickerBase extends SizedMixin(Focusable) {
354366 `Deprecation Notice: You no longer need to provide an sp-menu child to ${ this . tagName . toLowerCase ( ) } . Any styling or attributes on the sp-menu will be ignored.`
355367 ) ;
356368 }
357- this . reparentableChildren = Array . from (
358- ( deprecatedMenu || this ) . children
359- ) ;
369+ this . menuItems = [
370+ ... this . querySelectorAll ( `sp-menu-item` ) ,
371+ ] as MenuItem [ ] ;
360372 }
361373
362374 protected updated ( changedProperties : PropertyValues ) : void {
363375 super . updated ( changedProperties ) ;
364- if (
365- changedProperties . has ( 'value' ) &&
366- ! changedProperties . has ( 'selectedItem' ) &&
367- this . reparentableChildren
368- ) {
376+ if ( changedProperties . has ( 'value' ) && ! changedProperties . has ( 'selectedItem' ) ) {
369377 this . manageSelection ( ) ;
370378 }
371379 if ( changedProperties . has ( 'disabled' ) && this . disabled ) {
@@ -386,20 +394,15 @@ export class PickerBase extends SizedMixin(Focusable) {
386394 }
387395 }
388396
389- private async manageSelection ( ) : Promise < void > {
397+ protected async manageSelection ( ) : Promise < void > {
390398 /* c8 ignore next 3 */
391- if ( ! this . reparentableChildren ) {
392- return ;
393- }
394- if ( this . reparentableChildren . length ) {
399+ if ( this . menuItems . length > 0 ) {
395400 let selectedItem : MenuItem | undefined ;
396- this . reparentableChildren . map ( ( item ) => {
397- if ( item instanceof MenuItem ) {
398- if ( this . value === item . value && ! item . disabled ) {
399- selectedItem = item ;
400- } else {
401- item . selected = false ;
402- }
401+ this . menuItems . forEach ( ( item ) => {
402+ if ( this . value === item . value && ! item . disabled ) {
403+ selectedItem = item ;
404+ } else {
405+ item . selected = false ;
403406 }
404407 } ) ;
405408 if ( selectedItem ) {
@@ -409,12 +412,12 @@ export class PickerBase extends SizedMixin(Focusable) {
409412 this . value = '' ;
410413 this . selectedItem = undefined ;
411414 }
412- if ( this . open && this . optionsMenu ) {
415+ if ( this . open ) {
413416 this . optionsMenu . updateSelectedItemIndex ( ) ;
414417 }
415418 return ;
416419 }
417- if ( this . open && this . optionsMenu ) {
420+ if ( this . open ) {
418421 await this . optionsMenu . updateComplete ;
419422 if ( this . optionsMenu . menuItems . length ) {
420423 this . manageSelection ( ) ;
0 commit comments