xtal-sip
Version:
Dynamically "water" a custom element tag with the necessary dependencies to sprout the tag from an inert seedling to a thing of beauty.
79 lines (69 loc) • 2.72 kB
text/typescript
//import {getShadowContainer} from './getShadowContainer.js';
type Constructor<T = {}> = new (...args: any[]) => T;
declare global{
interface HTMLElement{
disconnectedCallback() : any;
}
}
const eventNames = ["animationstart", "MSAnimationStart", "webkitAnimationStart"];
export function addCSSListener(id: string, self: any, targetSelector: string, insertListener: any, customStyles: string = '', ){
// See https://davidwalsh.name/detect-node-insertion
if(self._boundInsertListeners === undefined){
self._boundInsertListeners = {};
}
const boundInsertListeners = self._boundInsertListeners;
if(boundInsertListeners[targetSelector] !== undefined) return;
const styleInner = /* css */`
@keyframes ${id} {
from {
opacity: 0.99;
}
to {
opacity: 1;
}
}
${targetSelector}{
animation-duration: 0.001s;
animation-name: ${id};
}
${customStyles}`;
const style = document.createElement('style');
style.innerHTML = styleInner;
self._host = self.getRootNode();//experimental <any>getShadowContainer((<any>this as HTMLElement));
if(self._host.nodeType === 9){
self._host = document.firstElementChild;
}
const hostIsShadow = self._host.localName !== 'html';
if(hostIsShadow){
self._host.appendChild(style);
}else{
document.head.appendChild(style);
}
boundInsertListeners[targetSelector] = insertListener.bind(self);
const container = hostIsShadow ? self._host : document;
eventNames.forEach(name =>{
container.addEventListener(name, boundInsertListeners[targetSelector], false);
})
}
export function observeCssSelector<TBase extends Constructor<HTMLElement>>(superClass: TBase) {
return class extends superClass {
_boundInsertListener!: any;
_host: any;
addCSSListener(id: string, targetSelector: string, insertListener: any, customStyles: string = ''){
addCSSListener(id, this, targetSelector, insertListener, customStyles);
}
disconnect(){
if(this._boundInsertListener){
const hostIsShadow = this._host.localName !== 'html';
const container = hostIsShadow ? this._host : document;
eventNames.forEach(name =>{
container.removeEventListener(name, this._boundInsertListener);
})
}
}
disconnectedCallback(){
this.disconnect();
if(super.disconnectedCallback !== undefined) super.disconnectedCallback();
}
}
}