Skip to main content

@virtualstate/x

union

CodeSandbox Demo

import { union } from "@virtualstate/x";

async function wait(ms = 10) {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

async function* left() {
  yield "Left 1";
  await wait(19);
  yield "Left 2";
  await wait(401);
  yield "Left 3";
}

function* middle() {
  yield "Middle 1";
  yield "Middle 2";
  yield "Middle 3";
}

async function* right() {
  yield "Right 1";
  await wait(401);
  yield "Right 2";
  yield "Right 3";
  await wait(19);
  yield "Right 4";
}

for await (const [leftResult, middleResult, rightResult] of union([
  left(),
  middle(),
  right()
])) {
  const result = { leftResult, middleResult, rightResult };
  console.log(result);
  document.body.innerHTML = JSON.stringify(result, undefined, "  ");
}

h

Demo Usage

import { h, createFragment } from "@virtualstate/x";

async function AsyncExample() {
  return await new Promise(
    resolve => setTimeout(resolve, 1500, `Async result: ${Math.random()}`)
  );
}

async function *Loading(options: unknown, child: VNode) {
  yield <>Loading!</>;
  yield child;
}

export async function InitialExample() {
  return (
    <div class="output">
      <h3>
        This is an example of various
        capabilities of this pattern
      </h3>
      <pre>
        <Loading>
          <AsyncExample />
        </Loading>
      </pre>
    </div>
  )
}

Working with a virtual node

Related Blog Post

The returned of h is a VNode:

export interface VNode {
  source: unknown;
  options?: object;
  children?: AsyncIterable<VNode[]>;
}

Scalar nodes created with h will be returned directly

import { h } from "@virtualstate/x";

const node = h(1);
const { source: one } = node;
console.log({ one }); // Logs { one: 1 }

Any scalar nodes with h that have children can be read using for await

const first = h("first");
const second = h("second");
const third = h("third");
const node = h("result", {}, first, second, third);

const { source: result, children } = node;
console.log({ result }); // Logs { result: "result" }

if (!children) throw new Error("Expected children");

for await (const results of children) {
  // Eventually Logs { results: ["first", "second", "third" ] }
  console.log({ results: results.map(node => node.source) });
}

Any function type can be used as a virtual node

import { h } from "@virtualstate/x";

function Fn() {
  return "Function ✨";
}
async function AsyncFn() {
  await new Promise<void>(queueMicrotask);
  return "Async Function 💡";
}
function *GeneratorFn() {
  yield "GeneratorFn Loading";
  yield "GeneratorFn 💥";
}
async function *AsyncGeneratorFn() {
  yield "AsyncGeneratorFn Loading";
  yield "AsyncGeneratorFn 🔥";
}
function Fns() {
  return [
    h(Fn),
    h(AsyncFn),
    h(GeneratorFn),
    h(AsyncGeneratorFn)
  ]
    .map(node => f("fn", { name: node.source.name }, node.source.name, node));
}

const { children } = f(Fns);

if (!children) throw new Error("Expected children");

for await (const results of children) {
  // Eventually Logs { results: ["Fn", "AsyncFn", "GeneratorFn", "AsyncGeneratorFn" ] }
  console.log({ results: results.map(node => node.options.name) });
}

Discord

Interested in talking more about the project? Find us on Discord

Contributing

Please see Contributing

Code of Conduct

This project and everyone participating in it is governed by the Code of Conduct listed here. By participating, you are expected to uphold this code. Please report unacceptable behavior to conduct@fabiancook.dev.

Licence

This repository is licensed under the MIT license.