Skip to content

Instantly share code, notes, and snippets.

@elclanrs
Last active December 10, 2017 02:38
Show Gist options
  • Save elclanrs/dea0e7515a0e2b1b6cd61753a8ce6b56 to your computer and use it in GitHub Desktop.
Save elclanrs/dea0e7515a0e2b1b6cd61753a8ce6b56 to your computer and use it in GitHub Desktop.
Web Component Simple Wrapper
<my-popover>
<p>Title Goes Here</p>
</my-popover>
// https://stackoverflow.com/questions/9368538/getting-an-array-of-all-dom-events-possible
const events = Object.getOwnPropertyNames(document)
.concat(Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(document))))
.concat(Object.getOwnPropertyNames(Object.getPrototypeOf(window)))
.filter((elem, idx, self) => {
return !elem.indexOf('on') &&
(document[elem] === null || typeof document[elem] === 'function') &&
self.indexOf(elem) === idx;
})
.map(evt => evt.replace(/^on/, ''));
function createComponent(selector, config) {
const { template = '', style = '', attributes = {} } = config;
const templateElem = document.createElement('template');
delete config.template;
delete config.style;
delete config.attributes;
templateElem.innerHTML = `
<style>${style}</style>
${template}
`.trim();
const comp = class extends HTMLElement {
static get observedAttributes() {
return Object.keys(attributes);
}
constructor() {
super();
const templateClone = templateElem.content.cloneNode(true);
this.attachShadow({ mode: 'open' }).appendChild(templateClone);
events.forEach(evtName => {
Array.from(this.shadowRoot.querySelectorAll(`[on-${evtName}]`)).forEach(elem => {
const methodName = elem.getAttribute([`on-${evtName}`]);
const method = this[methodName].bind(this);
elem.addEventListener(evtName, method);
});
});
Object.entries(attributes).forEach(([name, attr]) => {
if (!this.hasAttribute(name)) {
this[name] = attr;
}
})
}
};
Object.entries(attributes).forEach(([name, attr]) => {
Object.defineProperty(comp.prototype, name, {
get() {
return this[`_${name}`];
},
set(value) {
this[`_${name}`] = value;
if (typeof value === 'boolean') {
if (value) {
this.setAttribute(name, value);
} else {
this.removeAttribute(name);
}
} else {
this.setAttribute(name, value);
}
}
});
});
Object.assign(comp.prototype, config);
customElements.define(selector, comp);
return comp;
}
//
const PopoverComponent = createComponent('my-popover', {
template: `
<slot></slot>
<button on-click="toggle">Button</button>
`,
style: `
:host {
display: block;
width: 100px;
height: 100px;
background: red;
}
:host([disabled]) {
background: gray;
}
`,
attributes: {
position: 'top',
disabled: false
},
toggle() {
this.disabled = !this.disabled;
},
connectedCallback() {
console.log('Initialized!');
},
attributeChangedCallback(name, oldValue, newValue) {
console.log(name, oldValue, newValue);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment