Last active
November 30, 2021 00:23
-
-
Save brunovcosta/0007a2c82ee0c7e16bb5918a213532de to your computer and use it in GitHub Desktop.
Abstra Custom Element
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
const eventListeners = []; | |
function define({ | |
name, | |
initialState, | |
template, | |
listeners | |
}) { | |
customElements.define(name, | |
class extends HTMLElement { | |
$state = initialState(); | |
$refresh(partialSelector) { | |
if (partialSelector) { | |
const clone = this.cloneNode(); | |
clone.shadowRoot.innerHTML = template(this.$state); | |
const newPartials = Array.from(clone.shadowRoot.querySelectorAll(partialSelector)); | |
const oldPartials = Array.from(this.shadowRoot.querySelectorAll(partialSelector)); | |
if (newPartials.length !== oldPartials.length) throw new Error(`Can't partially refresh when selection count changes ${newPartials.length} !== ${oldPartials.length}`); | |
oldPartials.forEach((item,index) => item.outerHTML = newPartials[index].outerHTML); | |
} else { | |
this.shadowRoot.innerHTML = template(this.$state); | |
} | |
Object.keys(listeners ?? {}).forEach(key => { | |
const [selector, eventName] = key.split(" "); | |
const elements = Array.from(this.shadowRoot.querySelectorAll(selector)); | |
const listener = event => listeners[key](event, this); | |
elements.forEach(element => eventListeners.forEach(l => element.removeEventListener(eventName, l))); | |
elements.forEach(element => element.addEventListener(eventName, listener)); | |
eventListeners.push(listener); | |
}); | |
} | |
constructor() { | |
super(); | |
this.attachShadow({mode: 'open'}); | |
this.$refresh(); | |
} | |
} | |
); | |
} | |
const name = "todo-app" | |
const initialState = () => ({ | |
items: [] | |
}) | |
const listeners = { | |
".add click": (evt, instance) => { | |
const value = instance.shadowRoot.querySelector("#new-item").value; | |
instance.$state.items.push(value) | |
instance.$refresh(); | |
}, | |
".remove click": (evt, instance) => { | |
const index = evt.target.dataset.index; | |
instance.$state.items.splice(index, 1); | |
instance.$refresh(".items, .counter"); | |
} | |
} | |
const template = state => ` | |
<div class="title" style="box-shadow: 0 10px 10px rgba(0,0,0,0.2);padding: 50px"> | |
<h1>Todo list</h1> | |
<div class="items" style="display: flex; align-items: stretch;flex-direction: column"> | |
${state.items.map((item,index) => | |
`<div class="item" style="display: flex;"> | |
<label style="flex-grow: 1">${item}</label> | |
<button class="remove" data-index="${index}">×</button> | |
</div>` | |
).join("")} | |
</div> | |
<div class="new-item"> | |
<input id="new-item"/><button class="add">add</button> | |
</div> | |
<small class="counter">${state.items.length} items</small> | |
</div>` | |
define({ | |
name, | |
initialState, | |
template, | |
listeners | |
}); |
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
{ | |
"key": "todo-app", | |
"thumbnail": "https://place-hold.it/300", | |
"label": "Example button", | |
"description": "Lorem ipsum", | |
"component": "todo-app.js", | |
"parametersDefinition": { | |
"parameters": [] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment