@spectrum-web-components/dropdown
Advanced tools
Comparing version 0.3.8 to 0.4.0
@@ -6,2 +6,8 @@ # Change Log | ||
# [0.4.0](https://github.com/adobe/spectrum-web-components/compare/@spectrum-web-components/dropdown@0.3.8...@spectrum-web-components/dropdown@0.4.0) (2020-02-24) | ||
### Features | ||
- **dropdown:** open menu UI with overlay system ([9811eeb](https://github.com/adobe/spectrum-web-components/commit/9811eeb)) | ||
## [0.3.8](https://github.com/adobe/spectrum-web-components/compare/@spectrum-web-components/dropdown@0.3.7...@spectrum-web-components/dropdown@0.3.8) (2020-02-05) | ||
@@ -8,0 +14,0 @@ |
@@ -22,2 +22,7 @@ { | ||
{ | ||
"name": "placement", | ||
"type": "Placement", | ||
"default": "\"bottom-start\"" | ||
}, | ||
{ | ||
"name": "quiet", | ||
@@ -68,5 +73,11 @@ "type": "boolean", | ||
"name": "optionsMenu", | ||
"type": "Menu | null" | ||
"type": "Menu | undefined" | ||
}, | ||
{ | ||
"name": "placement", | ||
"attribute": "placement", | ||
"type": "Placement", | ||
"default": "\"bottom-start\"" | ||
}, | ||
{ | ||
"name": "quiet", | ||
@@ -90,5 +101,2 @@ "attribute": "quiet", | ||
{ | ||
"name": "onClick" | ||
}, | ||
{ | ||
"name": "onKeydown" | ||
@@ -120,8 +128,8 @@ }, | ||
{ | ||
"name": "default", | ||
"name": "label", | ||
"description": "The placeholder content for the dropdown" | ||
}, | ||
{ | ||
"name": "options", | ||
"description": "The menu with options that will display when the dropdown is open" | ||
"name": "", | ||
"description": "The menu of options that will display when the dropdown is open" | ||
} | ||
@@ -128,0 +136,0 @@ ] |
@@ -33,5 +33,5 @@ /* | ||
var(--spectrum-global-dimension-size-150)) + var(--spectrum-popover-border-size, | ||
var(--spectrum-alias-border-size-thin))))}#button:hover .dropdown{color:var(--spectrum-dropdown-icon-color-hover,var(--spectrum-alias-icon-color-hover))}#button.is-selected .placeholder{color:var(--spectrum-dropdown-placeholder-text-color-down,var(--spectrum-global-color-gray-900))}:host([invalid]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-validation-icon-color-error,var(--spectrum-semantic-negative-color-icon))}:host([disabled]) #button:hover .dropdown,:host([disabled]) .dropdown,:host([invalid][disabled]) .icon,:host([invalid][disabled]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-icon-color-disabled,var(--spectrum-alias-icon-color-disabled))}:host([disabled]) #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-disabled,var(--spectrum-alias-text-color-disabled))}#label.placeholder:hover{color:var(--spectrum-dropdown-placeholder-text-color-hover,var(--spectrum-alias-placeholder-text-color-hover))}#label.placeholder:active{color:var(--spectrum-dropdown-placeholder-text-color-mouse-focus,var(--spectrum-global-color-gray-900))}#button.focus-visible #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-key-focus,var(--spectrum-alias-placeholder-text-color-hover))}#button.focus-visible .dropdown{color:var(--spectrum-dropdown-icon-color-key-focus,var(--spectrum-alias-icon-color-focus))}sp-popover{width:100%}#label~.dropdown{margin-left:var(--spectrum-dropdown-icon-gap,var(--spectrum-global-dimension-size-100))} | ||
var(--spectrum-alias-border-size-thin))))}#button:hover .dropdown{color:var(--spectrum-dropdown-icon-color-hover,var(--spectrum-alias-icon-color-hover))}#button.is-selected .placeholder{color:var(--spectrum-dropdown-placeholder-text-color-down,var(--spectrum-global-color-gray-900))}:host([invalid]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-validation-icon-color-error,var(--spectrum-semantic-negative-color-icon))}:host([disabled]) #button:hover .dropdown,:host([disabled]) .dropdown,:host([invalid][disabled]) .icon,:host([invalid][disabled]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-icon-color-disabled,var(--spectrum-alias-icon-color-disabled))}:host([disabled]) #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-disabled,var(--spectrum-alias-text-color-disabled))}#label.placeholder:hover{color:var(--spectrum-dropdown-placeholder-text-color-hover,var(--spectrum-alias-placeholder-text-color-hover))}#label.placeholder:active{color:var(--spectrum-dropdown-placeholder-text-color-mouse-focus,var(--spectrum-global-color-gray-900))}#button.focus-visible #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-key-focus,var(--spectrum-alias-placeholder-text-color-hover))}#button.focus-visible .dropdown{color:var(--spectrum-dropdown-icon-color-key-focus,var(--spectrum-alias-icon-color-focus))}sp-popover{display:none}#label~.dropdown{margin-left:var(--spectrum-dropdown-icon-gap,var(--spectrum-global-dimension-size-100))} | ||
`; | ||
export default styles; | ||
//# sourceMappingURL=dropdown.css.js.map |
@@ -9,5 +9,6 @@ import { PropertyValues, CSSResultArray, TemplateResult } from 'lit-element'; | ||
import '@spectrum-web-components/popover'; | ||
import { Placement } from '@spectrum-web-components/overlay'; | ||
/** | ||
* @slot default - The placeholder content for the dropdown | ||
* @slot options - The menu with options that will display when the dropdown is open | ||
* @slot label - The placeholder content for the dropdown | ||
* @slot {"sp-menu"} - The menu of options that will display when the dropdown is open | ||
*/ | ||
@@ -21,11 +22,14 @@ export declare class DropdownBase extends Focusable { | ||
open: boolean; | ||
optionsMenu: Menu | null; | ||
optionsMenu?: Menu; | ||
placement: Placement; | ||
quiet: boolean; | ||
value: string; | ||
selectedItemText: string; | ||
private closeOverlay?; | ||
private popover?; | ||
protected listRole: string; | ||
protected itemRole: string; | ||
private placeholder?; | ||
constructor(); | ||
readonly focusElement: HTMLElement; | ||
onOptionsChange(): void; | ||
onButtonBlur(): void; | ||
@@ -38,5 +42,11 @@ protected onButtonClick(): void; | ||
toggle(): void; | ||
close(): void; | ||
private onOverlayClosed; | ||
private openMenu; | ||
private closeMenu; | ||
protected readonly buttonContent: TemplateResult[]; | ||
protected render(): TemplateResult; | ||
protected firstUpdated(changedProperties: PropertyValues): void; | ||
protected updated(changedProperties: PropertyValues): void; | ||
disconnectedCallback(): void; | ||
} | ||
@@ -43,0 +53,0 @@ export declare class Dropdown extends DropdownBase { |
@@ -26,5 +26,6 @@ /* | ||
import '@spectrum-web-components/popover'; | ||
import { Overlay } from '@spectrum-web-components/overlay'; | ||
/** | ||
* @slot default - The placeholder content for the dropdown | ||
* @slot options - The menu with options that will display when the dropdown is open | ||
* @slot label - The placeholder content for the dropdown | ||
* @slot {"sp-menu"} - The menu of options that will display when the dropdown is open | ||
*/ | ||
@@ -37,3 +38,3 @@ export class DropdownBase extends Focusable { | ||
this.open = false; | ||
this.optionsMenu = null; | ||
this.placement = 'bottom-start'; | ||
this.quiet = false; | ||
@@ -44,5 +45,3 @@ this.value = ''; | ||
this.itemRole = 'option'; | ||
this.onClick = this.onClick.bind(this); | ||
this.onKeydown = this.onKeydown.bind(this); | ||
this.addEventListener('click', this.onClick); | ||
this.addEventListener('sp-menu-item-query-role', (event) => { | ||
@@ -71,10 +70,7 @@ event.stopPropagation(); | ||
} | ||
if (this.open && this.optionsMenu) { | ||
return this.optionsMenu; | ||
} | ||
return this.button; | ||
} | ||
onOptionsChange() { | ||
this.optionsMenu = this.querySelector('sp-menu'); | ||
if (this.value) { | ||
this.requestUpdate('value'); | ||
} | ||
} | ||
onButtonBlur() { | ||
@@ -91,6 +87,2 @@ /* istanbul ignore if */ | ||
onButtonFocus() { | ||
if (this.open) { | ||
this.requestUpdate('open'); | ||
return; | ||
} | ||
/* istanbul ignore if */ | ||
@@ -103,10 +95,8 @@ if (typeof this.button === 'undefined') { | ||
onClick(event) { | ||
const path = event.composedPath(); | ||
const target = path.find((el) => { | ||
if (!(el instanceof Element) || this.optionsMenu === null) { | ||
return false; | ||
const target = event.target; | ||
/* istanbul ignore if */ | ||
if (!target || target.disabled) { | ||
if (target) { | ||
this.focus(); | ||
} | ||
return el.getAttribute('role') === this.optionsMenu.childRole; | ||
}); | ||
if (!target) { | ||
return; | ||
@@ -121,3 +111,3 @@ } | ||
/* istanbul ignore if */ | ||
if (this.optionsMenu === null) { | ||
if (!this.optionsMenu) { | ||
return; | ||
@@ -140,3 +130,5 @@ } | ||
} | ||
const selectedItem = this.querySelector('[selected]'); | ||
const parentElement = item.parentElement; | ||
const selectedItem = parentElement.querySelector('[selected]'); | ||
/* istanbul ignore if */ | ||
if (selectedItem) { | ||
@@ -152,2 +144,47 @@ selectedItem.selected = false; | ||
} | ||
close() { | ||
this.open = false; | ||
} | ||
onOverlayClosed() { | ||
this.close(); | ||
/* istanbul ignore else */ | ||
if (this.optionsMenu && this.placeholder) { | ||
const parentElement = this.placeholder.parentElement || | ||
this.placeholder.getRootNode(); | ||
/* istanbul ignore else */ | ||
if (parentElement) { | ||
parentElement.replaceChild(this.optionsMenu, this.placeholder); | ||
} | ||
} | ||
delete this.placeholder; | ||
} | ||
openMenu() { | ||
/* istanbul ignore if */ | ||
if (!this.popover || | ||
!this.button || | ||
!this.optionsMenu || | ||
this.optionsMenu.children.length === 0) | ||
return; | ||
this.placeholder = document.createComment('placeholder for optionsMenu'); | ||
const parentElement = this.optionsMenu.parentElement || this.optionsMenu.getRootNode(); | ||
/* istanbul ignore else */ | ||
if (parentElement) { | ||
parentElement.replaceChild(this.placeholder, this.optionsMenu); | ||
} | ||
this.popover.append(this.optionsMenu); | ||
// only use `this.offsetWidth` when Standard variant | ||
const menuWidth = !this.quiet && `${this.offsetWidth}px`; | ||
if (menuWidth) { | ||
this.popover.style.setProperty('width', menuWidth); | ||
} | ||
this.closeOverlay = Overlay.open(this.button, 'click', this.popover, { | ||
placement: this.placement, | ||
}); | ||
} | ||
closeMenu() { | ||
if (this.closeOverlay) { | ||
this.closeOverlay(); | ||
delete this.closeOverlay; | ||
} | ||
} | ||
get buttonContent() { | ||
@@ -163,3 +200,3 @@ return [ | ||
: html ` | ||
<slot></slot> | ||
<slot name="label">${this.label}</slot> | ||
`} | ||
@@ -198,11 +235,14 @@ </div> | ||
</button> | ||
<sp-popover direction="bottom" id="popover" ?open=${this.open}> | ||
<slot name="options" @slotchange=${this.onOptionsChange}> | ||
<sp-menu-item disabled> | ||
There are no options currently available. | ||
</sp-menu-item> | ||
</slot> | ||
</sp-popover> | ||
<sp-popover | ||
open | ||
id="popover" | ||
@click=${this.onClick} | ||
@sp-overlay-closed=${this.onOverlayClosed} | ||
></sp-popover> | ||
`; | ||
} | ||
firstUpdated(changedProperties) { | ||
super.firstUpdated(changedProperties); | ||
this.optionsMenu = this.querySelector('sp-menu'); | ||
} | ||
updated(changedProperties) { | ||
@@ -236,16 +276,26 @@ super.updated(changedProperties); | ||
} | ||
if (changedProperties.has('open') && this.open) { | ||
requestAnimationFrame(() => { | ||
/* istanbul ignore if */ | ||
if (this.optionsMenu === null) { | ||
return; | ||
} | ||
/* Trick :focus-visible polyfill into thinking keyboard based focus */ | ||
this.dispatchEvent(new KeyboardEvent('keydown', { | ||
code: 'Tab', | ||
})); | ||
this.optionsMenu.focus(); | ||
}); | ||
if (changedProperties.has('open')) { | ||
if (this.open) { | ||
this.openMenu(); | ||
requestAnimationFrame(() => { | ||
/* istanbul ignore if */ | ||
if (!this.optionsMenu) { | ||
return; | ||
} | ||
/* Trick :focus-visible polyfill into thinking keyboard based focus */ | ||
this.dispatchEvent(new KeyboardEvent('keydown', { | ||
code: 'Tab', | ||
})); | ||
this.optionsMenu.focus(); | ||
}); | ||
} | ||
else { | ||
this.closeMenu(); | ||
} | ||
} | ||
} | ||
disconnectedCallback() { | ||
this.open = false; | ||
super.disconnectedCallback(); | ||
} | ||
} | ||
@@ -268,2 +318,5 @@ __decorate([ | ||
__decorate([ | ||
property() | ||
], DropdownBase.prototype, "placement", void 0); | ||
__decorate([ | ||
property({ type: Boolean, reflect: true }) | ||
@@ -277,2 +330,5 @@ ], DropdownBase.prototype, "quiet", void 0); | ||
], DropdownBase.prototype, "selectedItemText", void 0); | ||
__decorate([ | ||
query('sp-popover') | ||
], DropdownBase.prototype, "popover", void 0); | ||
export class Dropdown extends DropdownBase { | ||
@@ -279,0 +335,0 @@ static get styles() { |
@@ -21,3 +21,3 @@ { | ||
], | ||
"version": "0.3.8", | ||
"version": "0.4.0", | ||
"description": "", | ||
@@ -49,8 +49,9 @@ "main": "lib/index.js", | ||
"@spectrum-web-components/menu": "^0.2.3", | ||
"@spectrum-web-components/menu-item": "^0.3.8", | ||
"@spectrum-web-components/popover": "^0.3.1", | ||
"@spectrum-web-components/menu-item": "^0.4.0", | ||
"@spectrum-web-components/overlay": "^0.3.0", | ||
"@spectrum-web-components/popover": "^0.3.2", | ||
"@spectrum-web-components/shared": "^0.4.3", | ||
"tslib": "^1.10.0" | ||
}, | ||
"gitHead": "02944b5006325e4ddc72f0a5f21b230d61401f0c" | ||
"gitHead": "458efe94228954db66b17c16312987c0778813c1" | ||
} |
@@ -19,5 +19,6 @@ ## Description | ||
```html | ||
<sp-dropdown> | ||
Select a Country with a very long label, too long in fact | ||
<sp-menu slot="options" role="listbox"> | ||
<sp-dropdown | ||
label="Select a Country with a very long label, too long in fact" | ||
> | ||
<sp-menu> | ||
<sp-menu-item> | ||
@@ -27,3 +28,3 @@ Deselect | ||
<sp-menu-item> | ||
Select Inverse | ||
Select inverse | ||
</sp-menu-item> | ||
@@ -34,10 +35,10 @@ <sp-menu-item> | ||
<sp-menu-item> | ||
Select and Mask... | ||
Select and mask... | ||
</sp-menu-item> | ||
<sp-menu-divider></sp-menu-divider> | ||
<sp-menu-item> | ||
Save Selection | ||
Save selection | ||
</sp-menu-item> | ||
<sp-menu-item disabled> | ||
Make Work Path | ||
Make work path | ||
</sp-menu-item> | ||
@@ -55,6 +56,6 @@ </sp-menu> | ||
<sp-dropdown | ||
label="Select a Country with a very long label, too long in fact" | ||
invalid | ||
> | ||
Select a Country with a very long label, too long in fact | ||
<sp-menu slot="options" role="listbox"> | ||
<sp-menu> | ||
<sp-menu-item> | ||
@@ -64,3 +65,3 @@ Deselect | ||
<sp-menu-item> | ||
Select Inverse | ||
Select inverse | ||
</sp-menu-item> | ||
@@ -71,10 +72,10 @@ <sp-menu-item> | ||
<sp-menu-item> | ||
Select and Mask... | ||
Select and mask... | ||
</sp-menu-item> | ||
<sp-menu-divider></sp-menu-divider> | ||
<sp-menu-item> | ||
Save Selection | ||
Save selection | ||
</sp-menu-item> | ||
<sp-menu-item disabled> | ||
Make Work Path | ||
Make work path | ||
</sp-menu-item> | ||
@@ -90,6 +91,6 @@ </sp-menu> | ||
<sp-dropdown | ||
label="Select a Country with a very long label, too long in fact" | ||
disabled | ||
> | ||
Select a Country with a very long label, too long in fact | ||
<sp-menu slot="options" role="listbox"> | ||
<sp-menu> | ||
<sp-menu-item> | ||
@@ -99,3 +100,3 @@ Deselect | ||
<sp-menu-item> | ||
Select Inverse | ||
Select inverse | ||
</sp-menu-item> | ||
@@ -106,10 +107,10 @@ <sp-menu-item> | ||
<sp-menu-item> | ||
Select and Mask... | ||
Select and mask... | ||
</sp-menu-item> | ||
<sp-menu-divider></sp-menu-divider> | ||
<sp-menu-item> | ||
Save Selection | ||
Save selection | ||
</sp-menu-item> | ||
<sp-menu-item disabled> | ||
Make Work Path | ||
Make work path | ||
</sp-menu-item> | ||
@@ -116,0 +117,0 @@ </sp-menu> |
@@ -33,4 +33,4 @@ /* | ||
var(--spectrum-global-dimension-size-150)) + var(--spectrum-popover-border-size, | ||
var(--spectrum-alias-border-size-thin))))}#button:hover .dropdown{color:var(--spectrum-dropdown-icon-color-hover,var(--spectrum-alias-icon-color-hover))}#button.is-selected .placeholder{color:var(--spectrum-dropdown-placeholder-text-color-down,var(--spectrum-global-color-gray-900))}:host([invalid]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-validation-icon-color-error,var(--spectrum-semantic-negative-color-icon))}:host([disabled]) #button:hover .dropdown,:host([disabled]) .dropdown,:host([invalid][disabled]) .icon,:host([invalid][disabled]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-icon-color-disabled,var(--spectrum-alias-icon-color-disabled))}:host([disabled]) #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-disabled,var(--spectrum-alias-text-color-disabled))}#label.placeholder:hover{color:var(--spectrum-dropdown-placeholder-text-color-hover,var(--spectrum-alias-placeholder-text-color-hover))}#label.placeholder:active{color:var(--spectrum-dropdown-placeholder-text-color-mouse-focus,var(--spectrum-global-color-gray-900))}#button.focus-visible #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-key-focus,var(--spectrum-alias-placeholder-text-color-hover))}#button.focus-visible .dropdown{color:var(--spectrum-dropdown-icon-color-key-focus,var(--spectrum-alias-icon-color-focus))}sp-popover{width:100%}#label~.dropdown{margin-left:var(--spectrum-dropdown-icon-gap,var(--spectrum-global-dimension-size-100))} | ||
var(--spectrum-alias-border-size-thin))))}#button:hover .dropdown{color:var(--spectrum-dropdown-icon-color-hover,var(--spectrum-alias-icon-color-hover))}#button.is-selected .placeholder{color:var(--spectrum-dropdown-placeholder-text-color-down,var(--spectrum-global-color-gray-900))}:host([invalid]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-validation-icon-color-error,var(--spectrum-semantic-negative-color-icon))}:host([disabled]) #button:hover .dropdown,:host([disabled]) .dropdown,:host([invalid][disabled]) .icon,:host([invalid][disabled]) .icon:not(.dropdown):not(.checkmark){color:var(--spectrum-dropdown-icon-color-disabled,var(--spectrum-alias-icon-color-disabled))}:host([disabled]) #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-disabled,var(--spectrum-alias-text-color-disabled))}#label.placeholder:hover{color:var(--spectrum-dropdown-placeholder-text-color-hover,var(--spectrum-alias-placeholder-text-color-hover))}#label.placeholder:active{color:var(--spectrum-dropdown-placeholder-text-color-mouse-focus,var(--spectrum-global-color-gray-900))}#button.focus-visible #label.placeholder{color:var(--spectrum-dropdown-placeholder-text-color-key-focus,var(--spectrum-alias-placeholder-text-color-hover))}#button.focus-visible .dropdown{color:var(--spectrum-dropdown-icon-color-key-focus,var(--spectrum-alias-icon-color-focus))}sp-popover{display:none}#label~.dropdown{margin-left:var(--spectrum-dropdown-icon-gap,var(--spectrum-global-dimension-size-100))} | ||
`; | ||
export default styles; |
@@ -40,6 +40,7 @@ /* | ||
import '@spectrum-web-components/popover'; | ||
import { Overlay, Placement } from '@spectrum-web-components/overlay'; | ||
/** | ||
* @slot default - The placeholder content for the dropdown | ||
* @slot options - The menu with options that will display when the dropdown is open | ||
* @slot label - The placeholder content for the dropdown | ||
* @slot {"sp-menu"} - The menu of options that will display when the dropdown is open | ||
*/ | ||
@@ -72,4 +73,7 @@ export class DropdownBase extends Focusable { | ||
public optionsMenu: Menu | null = null; | ||
public optionsMenu?: Menu; | ||
@property() | ||
public placement: Placement = 'bottom-start'; | ||
@property({ type: Boolean, reflect: true }) | ||
@@ -84,10 +88,14 @@ public quiet = false; | ||
private closeOverlay?: () => void; | ||
@query('sp-popover') | ||
private popover?: HTMLElement; | ||
protected listRole = 'listbox'; | ||
protected itemRole = 'option'; | ||
private placeholder?: Comment; | ||
public constructor() { | ||
super(); | ||
this.onClick = this.onClick.bind(this); | ||
this.onKeydown = this.onKeydown.bind(this); | ||
this.addEventListener('click', this.onClick); | ||
@@ -115,12 +123,8 @@ this.addEventListener( | ||
} | ||
if (this.open && this.optionsMenu) { | ||
return this.optionsMenu; | ||
} | ||
return this.button; | ||
} | ||
public onOptionsChange(): void { | ||
this.optionsMenu = this.querySelector('sp-menu'); | ||
if (this.value) { | ||
this.requestUpdate('value'); | ||
} | ||
} | ||
public onButtonBlur(): void { | ||
@@ -139,6 +143,2 @@ /* istanbul ignore if */ | ||
public onButtonFocus(): void { | ||
if (this.open) { | ||
this.requestUpdate('open'); | ||
return; | ||
} | ||
/* istanbul ignore if */ | ||
@@ -152,10 +152,8 @@ if (typeof this.button === 'undefined') { | ||
public onClick(event: Event): void { | ||
const path = event.composedPath(); | ||
const target = path.find((el) => { | ||
if (!(el instanceof Element) || this.optionsMenu === null) { | ||
return false; | ||
const target = event.target as MenuItem; | ||
/* istanbul ignore if */ | ||
if (!target || target.disabled) { | ||
if (target) { | ||
this.focus(); | ||
} | ||
return el.getAttribute('role') === this.optionsMenu.childRole; | ||
}) as MenuItem; | ||
if (!target) { | ||
return; | ||
@@ -171,3 +169,3 @@ } | ||
/* istanbul ignore if */ | ||
if (this.optionsMenu === null) { | ||
if (!this.optionsMenu) { | ||
return; | ||
@@ -192,3 +190,7 @@ } | ||
} | ||
const selectedItem = this.querySelector('[selected]') as MenuItem; | ||
const parentElement = item.parentElement as Element; | ||
const selectedItem = parentElement.querySelector( | ||
'[selected]' | ||
) as MenuItem; | ||
/* istanbul ignore if */ | ||
if (selectedItem) { | ||
@@ -206,2 +208,64 @@ selectedItem.selected = false; | ||
public close(): void { | ||
this.open = false; | ||
} | ||
private onOverlayClosed(): void { | ||
this.close(); | ||
/* istanbul ignore else */ | ||
if (this.optionsMenu && this.placeholder) { | ||
const parentElement = | ||
this.placeholder.parentElement || | ||
this.placeholder.getRootNode(); | ||
/* istanbul ignore else */ | ||
if (parentElement) { | ||
parentElement.replaceChild(this.optionsMenu, this.placeholder); | ||
} | ||
} | ||
delete this.placeholder; | ||
} | ||
private openMenu(): void { | ||
/* istanbul ignore if */ | ||
if ( | ||
!this.popover || | ||
!this.button || | ||
!this.optionsMenu || | ||
this.optionsMenu.children.length === 0 | ||
) | ||
return; | ||
this.placeholder = document.createComment( | ||
'placeholder for optionsMenu' | ||
); | ||
const parentElement = | ||
this.optionsMenu.parentElement || this.optionsMenu.getRootNode(); | ||
/* istanbul ignore else */ | ||
if (parentElement) { | ||
parentElement.replaceChild(this.placeholder, this.optionsMenu); | ||
} | ||
this.popover.append(this.optionsMenu); | ||
// only use `this.offsetWidth` when Standard variant | ||
const menuWidth = !this.quiet && `${this.offsetWidth}px`; | ||
if (menuWidth) { | ||
this.popover.style.setProperty('width', menuWidth); | ||
} | ||
this.closeOverlay = Overlay.open(this.button, 'click', this.popover, { | ||
placement: this.placement, | ||
}); | ||
} | ||
private closeMenu(): void { | ||
if (this.closeOverlay) { | ||
this.closeOverlay(); | ||
delete this.closeOverlay; | ||
} | ||
} | ||
protected get buttonContent(): TemplateResult[] { | ||
@@ -217,3 +281,3 @@ return [ | ||
: html` | ||
<slot></slot> | ||
<slot name="label">${this.label}</slot> | ||
`} | ||
@@ -253,12 +317,17 @@ </div> | ||
</button> | ||
<sp-popover direction="bottom" id="popover" ?open=${this.open}> | ||
<slot name="options" @slotchange=${this.onOptionsChange}> | ||
<sp-menu-item disabled> | ||
There are no options currently available. | ||
</sp-menu-item> | ||
</slot> | ||
</sp-popover> | ||
<sp-popover | ||
open | ||
id="popover" | ||
@click=${this.onClick} | ||
@sp-overlay-closed=${this.onOverlayClosed} | ||
></sp-popover> | ||
`; | ||
} | ||
protected firstUpdated(changedProperties: PropertyValues): void { | ||
super.firstUpdated(changedProperties); | ||
this.optionsMenu = this.querySelector('sp-menu') as Menu; | ||
} | ||
protected updated(changedProperties: PropertyValues): void { | ||
@@ -292,18 +361,29 @@ super.updated(changedProperties); | ||
} | ||
if (changedProperties.has('open') && this.open) { | ||
requestAnimationFrame(() => { | ||
/* istanbul ignore if */ | ||
if (this.optionsMenu === null) { | ||
return; | ||
} | ||
/* Trick :focus-visible polyfill into thinking keyboard based focus */ | ||
this.dispatchEvent( | ||
new KeyboardEvent('keydown', { | ||
code: 'Tab', | ||
}) | ||
); | ||
this.optionsMenu.focus(); | ||
}); | ||
if (changedProperties.has('open')) { | ||
if (this.open) { | ||
this.openMenu(); | ||
requestAnimationFrame(() => { | ||
/* istanbul ignore if */ | ||
if (!this.optionsMenu) { | ||
return; | ||
} | ||
/* Trick :focus-visible polyfill into thinking keyboard based focus */ | ||
this.dispatchEvent( | ||
new KeyboardEvent('keydown', { | ||
code: 'Tab', | ||
}) | ||
); | ||
this.optionsMenu.focus(); | ||
}); | ||
} else { | ||
this.closeMenu(); | ||
} | ||
} | ||
} | ||
public disconnectedCallback(): void { | ||
this.open = false; | ||
super.disconnectedCallback(); | ||
} | ||
} | ||
@@ -310,0 +390,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
119507
1466
115
11
+ Added@spectrum-web-components/icons@0.3.3(transitive)
+ Added@spectrum-web-components/menu-item@0.4.3(transitive)
- Removed@spectrum-web-components/menu-item@0.3.8(transitive)