JSFiddle - React, Tailwind, and code Playground
by elclanrs
HTML
<my-popover>
<p>Title Goes Here</p>
</my-popover>
JavaScript
// 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...