Skip to content

Instantly share code, notes, and snippets.

@tweinfeld
Last active December 12, 2020 18:33
Show Gist options
  • Save tweinfeld/f88e95faad45da4c662b7b3dbd6f5adb to your computer and use it in GitHub Desktop.
Save tweinfeld/f88e95faad45da4c662b7b3dbd6f5adb to your computer and use it in GitHub Desktop.
const createCustomElement = function(generator, attributes = []){
const
BUS = Symbol('bus'),
Element = class extends HTMLElement {
constructor(props) {
super(props);
const
instance = Reflect.construct(HTMLElement, [], this.constructor),
emitter = (function(){
const eventMap = new Map();
this[BUS] = function({ type, ...payload }){
[...(eventMap.get(type) || new Set()).values()].forEach((handler)=> handler(payload));
};
return {
on(type, handler){
eventMap.set(type, (eventMap.get(type) || new Set()).add(handler));
},
off(type, handler){
(eventMap.get(type) || new Set()).delete(handler);
}
};
}).call(this);
generator.call(instance, emitter);
}
attributeChangedCallback(attributeName, previousValue, newValue) { this[BUS]({ type: "attribute", name: attributeName, newValue, previousValue }); }
connectedCallback(){ this[BUS]({ type: "connected" }); }
disconnectedCallback(){ this[BUS]({ type: "disconnected" }); }
};
Element.observedAttributes = attributes;
return Element;
};
// Usage example
const myCustomElement = createCustomElement(function(life){
this.attachShadow({ mode: 'open' });
life.on('connected', ()=> console.log('Connected!'));
life.on('attribute', (payload)=> console.log('Attribute Changed!', payload));
life.on('disconnected', ()=> console.log('Disconnected!'));
}, ["disabled"]);
customElements.define('my-custom-element', myCustomElement);
const el = document.createElement('my-custom-element');
document.body.appendChild();
el.setAttribute('disabled', '');
document.body.removeChild(el);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment