// A plain custom element that demonstrates a reorder widget: one light-DOM // button and an ordered list. The SPA owns HTTP; this element only speaks the // summer-action / summer-result events. It makes no request and reads no // cookie or storage. A click reverses the current items (the simplest stand-in // for a drag reorder) and sends the new id order as the action's payload; the // returned data (its items array) arrives both as the `data` attribute and as // the summer-result event's detail.data, and is rendered with textContent. class AcmeDemoLookup extends HTMLElement { static get observedAttributes() { return ['data'] } constructor() { super() this.items = [] this.list = null this.addEventListener('summer-result', (event) => this.receive(event.detail && event.detail.data)) } connectedCallback() { if (this.firstChild) return const button = document.createElement('button') button.type = 'button' button.textContent = this.getAttribute('label') || '' button.addEventListener('click', () => { this.items = this.items.slice().reverse() this.render() const payload = { order: this.items.map((item) => item.id) } this.dispatchEvent(new CustomEvent('summer-action', { bubbles: true, composed: true, detail: { payload } })) }) this.list = document.createElement('ol') this.append(button, this.list) this.render() } attributeChangedCallback(name, _old, value) { if (name !== 'data') return try { this.receive(value === null ? null : JSON.parse(value)) } catch { this.receive(null) } } receive(data) { this.items = data && Array.isArray(data.items) ? data.items.filter((item) => item && typeof item === 'object') : [] this.render() } render() { if (!this.list) return this.list.textContent = '' for (const item of this.items) { const li = document.createElement('li') li.textContent = String(item.title == null ? item.id : item.title) this.list.append(li) } } } if (!customElements.get('acme-demo-lookup')) { customElements.define('acme-demo-lookup', AcmeDemoLookup) }