Last active
January 22, 2021 13:56
-
-
Save jpzwarte/067b3f5a59d2f4ecf956b5e643b661b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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