JSFiddle - React, Tailwind, and code Playground

author(s): Tao Xin

HTML

<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.6.1.nomodule.min.js"></script>

CSS

.label {
  font-weight: bold;
  display: inline-block;
  width: 100px;
}

JavaScript

const {div, input, span} = van.tags

const fullName = van.state(localStorage.getItem("fullName") ?? "Tao Xin")

// State persistence with `localStorage`
van.derive(() => localStorage.setItem("fullName", fullName.val))

// Defining multiple derived states
const firstName = van.state(), lastName = van.state()
van.derive(() => [firstName.val, lastName.val] = fullName.val.split(" "))

const elapsed = van.state(0)
setInterval(() => elapsed.val += .01, 10)

// Same as `elapsed`, but delay the state propagation by 1s
const delayed = van.state(0)
van.derive(() => setTimeout(v => delayed.val = v, 1000, elapsed.val))

// Same as `elapsed`, but throttle the state update to every 100ms
const throttled = van.state(0)
setInterval(() => throttled.val = elapsed.val, 100)

// Generate a data stream for all value updates of a given state `s`
const streamOf = s => {
  let resolver
  van.derive(() => resolver ? resolver({value: s.val, done: false}) : s.val)
  return {
    [Symbol.asyncIterator]: () => ({
      next: () => new Promise(resolve => resolver = resolve)
    })
  }
}

(async () => {
  // To subscribe the data stream
  for await (const v of streamOf(throttled)) {
    console.log("elapsed: ", v)
  }
  // You can also chain the data stream with `map`, `filter`, etc. by integrating with
  // rubico (https://rubico.land) or wu.js (https://fitzgen.github.io/wu.js/).
})()

van.add(document.body,
  div(
    span({class: "label"}, "fullName:"),
    input({type: "text", value: fullName, oninput: e => fullName.val = e.target.value}),
  ),
  div(span({class: "label"}, "firstName:"), () => firstName.val ?? ""),
  div(span({class: "label"}, "lastName:"), () => lastName.val ?? ""),
  div(span({class: "label"}, "elapsed:"), () => elapsed.val.toFixed(2)),
  div(span({class: "label"}, "delayed:"), () => delayed.val.toFixed(2)),
  div(span({class: "label"}, "throttled:"), () => throttled.val.toFixed(2)),
)