customElements.define('ts-list', class extends HTMLElement {
static observedAttributes = ['ix']
constructor() { super(); this.ix=0 }
connectedCallback() {
let sh = this.attachShadow({mode: 'open'})
sh.innerHTML=`
`
Array.from(this.children).map(x=>this.decorateChild(x))
sh.getElementById('up').onclick = e=> this.mv(-1)
sh.getElementById('dn').onclick = e=> this.mv(+1)
sh.getElementById('add').onclick = e=>{
let el = document.createElement('p')
this.insertBefore(el, this.children[this.ix].nextSibling)
this.decorateChild(el)
this.update()}}
decorateChild(el){
el.contentEditable = true
el.onclick = e=>this.setAttribute('ix', [].indexOf.call(this.children, e.target))}
attributeChangedCallback(key,old,val) {
switch (key) {
case 'ix': { this.ix = parseInt(val); this.update() }}}
get value() { return this.children[this.ix].innerText }
get values() { return Array.from(this.children).map(x=>x.innerText) }
go(ix){ this.setAttribute('ix', this.ix=ix);this.update() }
mv(di){ this.go(Math.min(this.children.length-1, Math.max(0,this.ix + di))) }
update() { let cs = Array.from(this.children)
cs.forEach(c=>{c.classList.remove('active') })
if (this.ix
ts-list { display:block; width: 200px; border: solid #333 2px; }
p { padding: 2px; border: solid silver 1px; }
p.active { background: silver }
`
document.body.innerHTML=`
hello?
do the dishes
`