npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@virtualstate/focus

v1.4.10-alpha.4

Published

WIP implementation of [@virtualstate/fringe](https://github.com/virtualstate/x/blob/main/packages/fringe)

Downloads

156

Readme

@virtualstate/focus

WIP implementation of @virtualstate/fringe

This project is in semver alpha stage

Support

Node.js supported Deno supported Bun supported

Test Coverage

94.33%25 lines covered 94.33%25 statements covered 91.92%25 functions covered 84.7%25 branches covered

How to read JSX trees

The actual JSX node

A single JSX node is something we can inspect directly without any additional resolution (that may require async)

This can tell us things like, what kind of node it is, for example through its tagName, type property, or some other identifying property, this lets us tell forms from inputs, identify fragment nodes, or identify an associated class or function's name.

name

Through focus, you can use the name accessor

const { name } = await import("@virtualstate/focus");

node = <named />;

ok(name(node) === "named");

properties

JSX nodes can have key value pairs associated to them, these can be used for attributes, options, or properties, depending on what the node will be used for!

You can get an object with these values using the properties accessor

const { properties } = await import("@virtualstate/focus");

node = <named key="value" type="text" />;
object = properties(node);

ok<object>(object);
ok(object.key === "value");
ok(object.type === "text");

Async + Other Accessors

children

JSX nodes can have children nodes associated with them, this lets us create trees and graphs with JSX

Children may be resolvable completely synchronously, or async, either way, we use an async interface to our JSX node's children to ensure a consistent API across all nodes, and allowing this resolution to be freely swapped behind the scenes without changing dependent implementation.

One way we can read this tree is as if each node was a parent to some children, if we need to access those same children's children, we just repeat the same process again, until we have explored the entire tree.

To access a JSX node's children, use the children accessor

const { children } = await import("@virtualstate/focus");

tree = (
  <parent>
    <first />
    <second />
  </parent>
);

snapshot = await children(tree);

ok<Array<unknown>>(Array.isArray(snapshot));

ok(name(snapshot[0]) === "first");
ok(name(snapshot[1]) === "second");

Sometimes a JSX node may have multiple representations of what it's child state looks like, instead of using await with the result of children, we can instead use for await

This may be useful where there is some delay in one of the child node's from resolving

async function Component() {
  await new Promise<void>((resolve) => setTimeout(resolve, 10));
  return <second />;
}

tree = (
  <parent>
    <first />
    <Component />
  </parent>
);

for await (snapshot of children(tree)) {
  ok(name(snapshot[0]) === "first");
  ok(!snapshot[1] || name(snapshot[1]) === "second");
}

childrenSettled

Some children may also throw errors, meaning you may want some way to observe the state of each individual child node, using children that are fulfilled, and deciding what to do with children that rejected

For this you can use the childrenSettled accessor, this has both the await and for await functionality like children

const { childrenSettled } = await import("@virtualstate/focus");

async function ComponentThrows() {
  await new Promise<void>((resolve) => setTimeout(resolve, 10));
  throw new Error("Some error!");
}

tree = (
  <parent>
    <first />
    <ComponentThrows />
  </parent>
);

snapshot = await childrenSettled(tree);
ok(snapshot[0].status === "fulfilled");
ok(snapshot[1].status === "rejected");
for await (snapshot of childrenSettled(tree)) {
  ok(snapshot[0].status === "fulfilled");
  ok(!snapshot[1] || snapshot[1].status === "rejected");
}

descendants

Instead of just the direct children of a single JSX node, you may want to find out all descendants that you can reach

For this, you can use the descendants accessor

const { descendants } = await import("@virtualstate/focus");

tree = (
  <parent>
    <first />
    <second>
      <third />
    </second>
  </parent>
);
snapshot = await descendants(tree);
ok(name(snapshot[0]) === "first");
ok(name(snapshot[1]) === "second");
ok(name(snapshot[2]) === "third");

As with children, descendants to can be accessed through for await

for await (snapshot of descendants(tree)) {
  ok(name(snapshot[0]) === "first");
  ok(name(snapshot[1]) === "second");
  ok(!snapshot[2] || name(snapshot[2]) === "third");
}

descendantsSettled

You may want to be able to observe the resolution state of all descendants, as with childrenSettled

For this you can use the descendantsSettled accessor

const { descendantsSettled } = await import("@virtualstate/focus");

tree = (
  <parent>
    <first />
    <second>
      <ComponentThrows />
    </second>
  </parent>
);

snapshot = await descendantsSettled(tree);
ok(snapshot[0].status === "fulfilled");
ok(snapshot[1].status === "fulfilled");
ok(snapshot[2].status === "rejected");
for await (snapshot of descendantsSettled(tree)) {
  ok(snapshot[0].status === "fulfilled");
  ok(snapshot[1].status === "fulfilled");
  ok(!snapshot[2] || snapshot[2].status === "rejected");
}

Because we can expose a bit more information with descendantsSettled, you can also access the parent of an individual status object.

This is helpful when re-creating a tree from these descendants, or creating associations between them.

snapshot = await descendantsSettled(tree);
ok(snapshot[1].status === "fulfilled");
ok(snapshot[2].parent === snapshot[1].value);

This can also be accessed using through the for await pattern:

for await (snapshot of descendantsSettled(tree)) {
  ok(snapshot[1].status === "fulfilled");
  ok(!snapshot[2] || snapshot[2].parent === snapshot[1].value);
}

raw

The value you have access to, returned from the JSX node creation process, may not be the original representation used for the JSX node. This original raw representation may be helpful when creating new accessor functions, or what to inspect source definitions of component functions.

If there is another representation available, the raw accessor can be used to access it, if there is no raw representation, then that means the passed node is a raw representation itself, which is returned by default.

const { raw } = await import("@virtualstate/focus");

node = <named />;
rawNode = raw(node);
ok(name(rawNode) === "named");

proxy

To provide a new interface for a JSX node, or provide a different object completely, while still providing support for the above JSX accessors, the proxy function can be used

const { proxy } = await import("@virtualstate/focus");

node = <named />;

api = { name };
proxied = proxy(node, api);
ok(proxied.name === "named");
api = { someAccessorName: name };
proxied = proxy(node, api);
ok(proxied.someAccessorName === "named");

If a instance accessor is provided, then this can be used to provide a new object completely

api = {
  instance() {
    return { name: Math.random(), source: Math.random() };
  },
};
proxied = proxy(node, api);

ok(typeof proxied.name === "number");
ok(typeof proxied.source === "number");
ok(name(proxied) === "named");

When instance is used, raw becomes useful:

rawNode = raw(proxied);
ok(name(rawNode) === "named");
ok(typeof rawNode.name !== "number");
ok(rawNode === raw(node));

If you need to access the original instance that is being proxied, you can use the instance accessor.

const { instance } = await import("@virtualstate/focus");

staticInstance = { something: 1 };
api = {
  instance() {
    return staticInstance;
  },
};
proxied = proxy(node, api);
nodeInstance = instance(proxied);
ok(typeof proxied.something === "number");
ok(nodeInstance === staticInstance);
ok(nodeInstance !== proxied);