Skip to content

Instantly share code, notes, and snippets.

@jpzwarte
Last active January 22, 2021 13:56
Show Gist options
  • Save jpzwarte/067b3f5a59d2f4ecf956b5e643b661b4 to your computer and use it in GitHub Desktop.
Save jpzwarte/067b3f5a59d2f4ecf956b5e643b661b4 to your computer and use it in GitHub Desktop.
<dna-popover
onPopoverChange={(event: CustomEvent<boolean>) => this.onPopoverChange(event)}
id={this.popoverId}
placement="right"
>
<dna-shell-menu-popover label={this.label}>
<dna-portal ref={(el: HTMLDnaPortalElement) => (this.portalElement = el)}>
<slot></slot>
</dna-portal>
</dna-shell-menu-popover>
</dna-popover>
import { Component, ComponentInterface, Element, JSX, Method, h } from '@stencil/core';
import { equals } from '../../utils/array';
@Component({
tag: 'dna-portal',
styles: `
:host {
display: contents;
}
`,
shadow: true
})
export class Portal implements ComponentInterface {
/** Elements to be transported. */
private elements: Element[];
/** The origin of the transported elements. */
private originElement: HTMLElement;
/** The transported elements. */
private transportedElements: Element[];
/** The host element. */
@Element() el: HTMLElement;
render(): JSX.Element {
return <slot onSlotchange={(event: Event) => this.onSlotchange(event)}></slot>;
}
@Method()
async transport(): Promise<void> {
if (this.elements) {
this.transportedElements = this.elements;
this.el.append(...this.elements);
}
}
@Method()
async restore(): Promise<void> {
if (this.originElement && this.transportedElements) {
this.originElement.append(...this.transportedElements);
this.transportedElements = null;
}
}
onSlotchange(event: Event): void {
let slot = event.target as HTMLSlotElement,
elements = slot.assignedElements();
// Check if we have nested slots. If so, then append the menu items
// from the parent slot to the light DOM of this element, since
// this element will be moved elsewhere in the DOM for the popover.
if (elements.length === 1 && elements[0].tagName === 'SLOT') {
slot = elements[0] as HTMLSlotElement;
elements = slot.assignedElements();
}
// Filter out any slots
elements = elements.filter(e => e.tagName !== 'SLOT');
// We have to check whether the assigned elements have already been transported
// otherwise we will get in an infinite loop
if (elements.length === 0 || equals(elements, this.transportedElements)) {
return;
}
this.originElement = elements[0].parentElement;
this.elements = elements;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment