import { h, Html, RxAble } from 'rx'
import * as rx from 'rx'
const imbricatedMaps =
rx.withState(1, counter => [
counterComponent({
value: counter,
onSub: () => counter.update(n => n - 1),
onAdd: () => counter.update(n => n + 1)
}),
counter.map(c1 => {
console.log('c1')
return [
h('div', 'Inside first count'),
counter.map(c2 => {
console.log('c2')
return h('div', `Inside second count ${c2}`)
})
]
})
])
const flatMap =
rx.withState(1, counter => [
counterComponent({
value: counter,
onSub: () => counter.update(n => n - 1),
onAdd: () => counter.update(n => n + 1)
}),
counter.flatMap(c1 => {
console.log('c1')
return counter.map(c2 => {
console.log('c2')
return h('div', `Inside second count ${c2}`)
})
})
])
const checkbox =
rx.withState(false, checked => [
checkboxComponent({
label: 'Checkbox',
isChecked: checked,
onCheck: (isChecked: boolean) => checked.update(_ => isChecked),
}),
h('div', checked.map(isChecked => isChecked ? 'C’est coché!' : 'Ça n’est pas coché'))
])
const rxChildren =
rx.withState(3, count => [
h('input', {
type: 'number',
value: count,
onchange: (event: Event) => count.update(_ => parseInt((event.target as HTMLInputElement).value))
}),
h('div', 'FOO'),
count.map(n => Array(n).fill(null).map((_, i) => h('div', `A ${i}!`))),
h('div', 'BAR'),
count.map(n => Array(n).fill(null).map((_, i) => h('div', `B ${i}!`))),
h('div', 'BAZ')
])
const nodesCancel =
rx.withState(false, checked => [
checkboxComponent({
label: 'Checkbox',
isChecked: checked,
onCheck: (isChecked: boolean) => checked.update(_ => isChecked),
}),
checked.map(isChecked => isChecked ? rxChildren : undefined)
])
const counters =
rx.withState>([], counters => {
return [
counterComponent({
value: counters.map(cs => cs.length),
onSub: () => counters.update(cs => cs.slice(0, -1)),
onAdd: () => counters.update(cs => cs.concat(0))
}),
h('hr'),
h('div', { style: 'margin-top: 1rem' }, counters.map(cs =>
cs.map((c, i) =>
counterComponent({
value: c,
onSub: () => counters.update(cs => {
cs[i] = c - 1
return cs
}),
onAdd: () => counters.update(cs => {
cs[i] = c + 1
return cs
})
})
)
))
]
})
const rows =
rx.withState(1, count => [
h('input', {
type: 'number',
value: count,
onchange: (event: Event) => count.update(_ => parseInt((event.target as HTMLInputElement).value))
}),
count.map(n => Array(n).fill(null).map((_, i) => h('div', i)))
])
const chrono =
rx.withState(false, isChecked => [
checkboxComponent({
label: 'Show counter',
isChecked,
onCheck: b => isChecked.update(_ => b)
}),
isChecked.map(b => b && rx.withState(0, elapsed => {
const interval = window.setInterval(
() => elapsed.update(n => n + 1),
1000
)
return h(
'div',
{ onunmount: () => clearInterval(interval) },
elapsed
)
}))
])
const doubleMapChild =
rx.withState(true, isEven =>
rx.withState('', search => {
const books = [...Array(50).keys()]
const filteredBooks = isEven.flatMap(f => search.map(s =>
books.filter(b =>
(f ? b % 2 === 0 : b % 2 === 1) &&
(s === '' || b.toString().includes(s)))))
return [
checkboxComponent({
label: 'Even?',
isChecked: isEven,
onCheck: checked => isEven.update(_ => checked)
}),
h(
'input',
{ oninput: (event: Event) => search.update(_ => (event.target as HTMLInputElement).value)
, style: 'margin-left: 1rem'
}
),
h('hr'),
isEven.map(b =>
b
? filteredBooks.map(xs => `isEven (${xs.length})`)
: filteredBooks.map(xs => `isOdd (${xs.length})`)
),
h('hr'),
filteredBooks.map(bs => bs.map(b => h('div', b))),
h('hr')
]
})
)
const seq =
rx.withState(0, a =>
rx.withState(0, b =>
rx.withState(0, c => [
counterComponent({
value: a,
onSub: () => a.update(n => n - 1),
onAdd: () => a.update(n => n + 1)
}),
counterComponent({
value: b,
onSub: () => b.update(n => n - 1),
onAdd: () => b.update(n => n + 1)
}),
counterComponent({
value: c,
onSub: () => c.update(n => n - 1),
onAdd: () => c.update(n => n + 1)
}),
rx.sequence2([a, b, c]).map(xs => xs.reduce((a, b) => a + b, 0))
])
)
)
const indirectCheckbox =
rx.withState(false, checked => [
checkboxComponent({
label: 'C1',
isChecked: checked,
onCheck: (b: boolean) => checked.update(_ => b)
}),
checkboxComponent({
label: 'C2',
isChecked: checked,
onCheck: (b: boolean) => checked.update(_ => b)
})
])
// Checkbox
interface CheckboxParams {
label: RxAble
isChecked: RxAble
onCheck: (isChecked: boolean) => void
}
function checkboxComponent({ label, isChecked, onCheck }: CheckboxParams) {
return h('label',
h('input',
{ type: 'checkbox',
onchange: (event: Event) => onCheck((event.target as HTMLInputElement).checked),
checked: isChecked,
}
),
label
)
}
// Counter
interface CounterParams {
value: RxAble
onAdd: () => void
onSub: () => void
}
function counterComponent({ value, onAdd, onSub}: CounterParams) {
return h('div',
[ h('span', { style: 'margin-right: 5px' }, value),
h('button', { onclick: () => onSub() }, '-'),
h('button', { onclick: () => onAdd() }, '+'),
]
)
}
// View
interface Item {
name: string
html: Html
}
const view = rx.withState('imbricatedMaps', exVar => {
const menuItem = ({ name }: Item) =>
h('li',
h('button',
{
onclick: () => exVar.update(_ => name),
className: exVar.map(ex => ex == name && 'selected')
},
name
)
)
const items: Array- = [
{ name: 'imbricatedMaps', html: imbricatedMaps },
{ name: 'flatMap', html: flatMap },
{ name: 'checkbox', html: checkbox },
{ name: 'rxChildren', html: rxChildren },
{ name: 'nodesCancel', html: nodesCancel },
{ name: 'counters', html: counters },
{ name: 'rows', html: rows },
{ name: 'chrono', html: chrono },
{ name: 'doubleMapChild', html: doubleMapChild },
{ name: 'seq', html: seq },
{ name: 'indirectCheckbox', html: indirectCheckbox },
]
return [
h('header', h('h1', 'Rx')),
h('main',
h('nav',
h('ul', items.map(menuItem))
),
h('section',
exVar.map(ex => {
const item = items.find(item => item.name == ex)
return item && item.html
})
)
)
]
})
rx.mount(document.body, view)