@virtualstate/x
In depth documentation coming soon!
If you want to get started, fork or clone the virtualstate.dev repository for an already set up project.
Running Examples
To run the examples located at packages/examples see:
Running examples with Deno
deno run \ *[main]
--import-map=https://cdn.skypack.dev/@virtualstate/deno/import-map.json \
--allow-net \
https://cdn.skypack.dev/@virtualstate/examples/lib/log.js
Running examples with Node
git clone https://github.com/virtualstate/x.git
cd x
yarn
yarn examples:log
h
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
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) });
}
union
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, " ");
}
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.