Web components + superfine
<title>Currency Coverter</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="module">
import { h, patch } from 'https://unpkg.com/superfine?module'
//import { h, patch } from './superfine.js'
const Numberbox = self => ({
type: 'number',
value: self.dataCount,
oninput: e => self.dataCount = e.target.value
})
const Increment = self => ({
onclick: e => self.dataCount += 1
})
const Decrement = self => ({
onclick: e => self.dataCount -= 1
})
const CounterTemplate = self => h('span', {},
h('style', {}, `
input, button {
font-size: 2rem;
touch-action: manipulation;
}
`),
h('input' , Numberbox(self)),
h('button', Decrement(self), '-'),
h('button', Increment(self), '+'),
)
export class Counter extends HTMLElement {
constructor() {
super()
this.attachShadow({mode:'open'})
this.render = (node => () => {
node = patch(node, CounterTemplate(this), this.shadowRoot)
})()
this.render()
}
get dataCount() {
return +this.dataset.count || 0
//return JSON.parse(this.dataset.xxx)
}
set dataCount(newVal) {
this.dataset.count = +newVal || 0
//this.dataset.xxx = JSON.stringify(newVal)
}
attributeChangedCallback(attrName, oldVal, newVal) {
if(oldVal != newVal) this.render()
}
static get observedAttributes() {
return ['data-count']
}
}
customElements.define('x-counter', Counter)
//==========================================================
const Rate = self =>
({
id: 'rate',
'data-count': self.dataset.rate
})
const Dollars = self =>
({
id: 'dollars',
'data-count': self.dataset.dollars
})
const ExchangerTemplate = self => h('div', {},
h('style', {}, `
h1 {
font-size: 4rem;
}
span {
font-size: 2rem;
}
`),
h('h1', {}, '¥' + self.dataset.yen),
h('span', {}, 'rate'), h('x-counter', Rate(self)),
h('br', {}),
h('span', {}, 'doll'), h('x-counter', Dollars(self)),
)
const observe = (targets, filter, clallback) => {
const observer = new MutationObserver(clallback)
const config = { attributes:true, attributeFilter:[filter] }
for(let t of targets) observer.observe(t, config)
}
export class Exchanger extends HTMLElement {
constructor() {
super()
this.dataset.rate = this.dataset.rate || 109
this.dataset.dollars = this.dataset.dollars || 1
this.dataset.yen = +this.dataset.rate * +this.dataset.dollars
this.attachShadow({mode:'open'})
this.render = (node => () => {
node = patch(node, ExchangerTemplate(this), this.shadowRoot)
})()
this.render()
const $ = s => this.shadowRoot.querySelector(s)
const rate = $('#rate'), dollars = $('#dollars')
observe([rate, dollars], 'data-count', () => {
this.dataset.yen = rate.dataCount * dollars.dataCount
this.dataset.rate = rate.dataCount
this.dataset.dollars = dollars.dataCount
})
}
attributeChangedCallback(attrName, oldVal, newVal) {
if(oldVal != newVal) this.render()
}
static get observedAttributes() {
return ['data-rate', 'data-dollars']
}
}
customElements.define('x-exchanger', Exchanger)
</script>
<body>
<x-exchanger data-rate="110"></x-exchanger>
</body>