{"id":20961473,"url":"https://github.com/virtualstate/focus","last_synced_at":"2026-05-08T13:18:45.676Z","repository":{"id":42081551,"uuid":"464449859","full_name":"virtualstate/focus","owner":"virtualstate","description":"JSX implementation","archived":false,"fork":false,"pushed_at":"2022-10-14T08:30:39.000Z","size":960,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-21T18:51:33.744Z","etag":null,"topics":["deno","jsx","jsx-reader","jsx-transform","jsxgraph","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/virtualstate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-28T11:11:04.000Z","updated_at":"2023-06-02T00:39:54.000Z","dependencies_parsed_at":"2023-01-20T01:18:09.911Z","dependency_job_id":null,"html_url":"https://github.com/virtualstate/focus","commit_stats":null,"previous_names":[],"tags_count":129,"template":false,"template_full_name":null,"purl":"pkg:github/virtualstate/focus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Ffocus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Ffocus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Ffocus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Ffocus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/virtualstate","download_url":"https://codeload.github.com/virtualstate/focus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/virtualstate%2Ffocus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32781992,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deno","jsx","jsx-reader","jsx-transform","jsxgraph","typescript"],"created_at":"2024-11-19T02:13:50.738Z","updated_at":"2026-05-08T13:18:45.661Z","avatar_url":"https://github.com/virtualstate.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `@virtualstate/focus`\n\nWIP implementation of [@virtualstate/fringe](https://github.com/virtualstate/x/blob/main/packages/fringe)\n\nThis project is in semver alpha stage\n\n[//]: # (badges)\n\n### Support\n\n ![Node.js supported](https://img.shields.io/badge/node-%3E%3D16.0.0-blue) ![Deno supported](https://img.shields.io/badge/deno-%3E%3D1.17.0-blue) ![Bun supported](https://img.shields.io/badge/bun-%3E%3D0.1.11-blue) \n\n### Test Coverage\n\n ![94.33%25 lines covered](https://img.shields.io/badge/lines-94.33%25-brightgreen) ![94.33%25 statements covered](https://img.shields.io/badge/statements-94.33%25-brightgreen) ![91.92%25 functions covered](https://img.shields.io/badge/functions-91.92%25-brightgreen) ![84.7%25 branches covered](https://img.shields.io/badge/branches-84.7%25-brightgreen)\n\n[//]: # (badges)\n\n[//]: # (src/trying-to-write-documentation/accessors-how.tsx)\n\n# How to read JSX trees\n\n# The actual JSX node\n\nA single JSX node is something we can inspect directly without any additional resolution (that may require async)\n\nThis can tell us things like, what kind of node it is, for example through its tagName, type property, or some other\nidentifying property, this lets us tell forms from inputs, identify fragment nodes, or identify an associated class or\nfunction's name.\n\n## name\n\nThrough focus, you can use the `name` accessor\n\n```typescript jsx\nconst { name } = await import(\"@virtualstate/focus\");\n\nnode = \u003cnamed /\u003e;\n\nok(name(node) === \"named\");\n```\n\n## properties\n\nJSX nodes can have key value pairs associated to them, these can be used for attributes, options, or properties,\ndepending on what the node will be used for!\n\nYou can get an object with these values using the `properties` accessor\n\n```typescript jsx\nconst { properties } = await import(\"@virtualstate/focus\");\n\nnode = \u003cnamed key=\"value\" type=\"text\" /\u003e;\nobject = properties(node);\n\nok\u003cobject\u003e(object);\nok(object.key === \"value\");\nok(object.type === \"text\");\n```\n\n# Async + Other Accessors\n\n## children\n\nJSX nodes can have children nodes associated with them, this lets us create trees and graphs with JSX\n\nChildren may be resolvable completely synchronously, or async, either way, we use an async interface to our\nJSX node's children to ensure a consistent API across all nodes, and allowing this\nresolution to be freely swapped behind the scenes without changing dependent implementation.\n\nOne way we can read this tree is as if each node was a parent to some children, if we need to access\nthose same children's children, we just repeat the same process again, until we have explored the entire tree.\n\nTo access a JSX node's children, use the `children` accessor\n\n```typescript jsx\nconst { children } = await import(\"@virtualstate/focus\");\n\ntree = (\n  \u003cparent\u003e\n    \u003cfirst /\u003e\n    \u003csecond /\u003e\n  \u003c/parent\u003e\n);\n\nsnapshot = await children(tree);\n\nok\u003cArray\u003cunknown\u003e\u003e(Array.isArray(snapshot));\n\nok(name(snapshot[0]) === \"first\");\nok(name(snapshot[1]) === \"second\");\n```\n\nSometimes a JSX node may have multiple representations of what it's child state looks like,\ninstead of using `await` with the result of `children`, we can instead use `for await`\n\nThis may be useful where there is some delay in one of the child node's from resolving\n\n```typescript jsx\nasync function Component() {\n  await new Promise\u003cvoid\u003e((resolve) =\u003e setTimeout(resolve, 10));\n  return \u003csecond /\u003e;\n}\n\ntree = (\n  \u003cparent\u003e\n    \u003cfirst /\u003e\n    \u003cComponent /\u003e\n  \u003c/parent\u003e\n);\n\nfor await (snapshot of children(tree)) {\n  ok(name(snapshot[0]) === \"first\");\n  ok(!snapshot[1] || name(snapshot[1]) === \"second\");\n}\n```\n\n## childrenSettled\n\nSome children may also throw errors, meaning you may want some way to observe the state of each individual\nchild node, using children that are fulfilled, and deciding what to do with children that rejected\n\nFor this you can use the `childrenSettled` accessor, this has both the `await` and `for await` functionality\nlike `children`\n\n```typescript jsx\nconst { childrenSettled } = await import(\"@virtualstate/focus\");\n\nasync function ComponentThrows() {\n  await new Promise\u003cvoid\u003e((resolve) =\u003e setTimeout(resolve, 10));\n  throw new Error(\"Some error!\");\n}\n\ntree = (\n  \u003cparent\u003e\n    \u003cfirst /\u003e\n    \u003cComponentThrows /\u003e\n  \u003c/parent\u003e\n);\n\nsnapshot = await childrenSettled(tree);\nok(snapshot[0].status === \"fulfilled\");\nok(snapshot[1].status === \"rejected\");\n```\n\n\n\n```typescript jsx\nfor await (snapshot of childrenSettled(tree)) {\n  ok(snapshot[0].status === \"fulfilled\");\n  ok(!snapshot[1] || snapshot[1].status === \"rejected\");\n}\n```\n\n## descendants\n\nInstead of just the direct children of a single JSX node, you may want to find out all descendants that you can reach\n\nFor this, you can use the `descendants` accessor\n\n```typescript jsx\nconst { descendants } = await import(\"@virtualstate/focus\");\n\ntree = (\n  \u003cparent\u003e\n    \u003cfirst /\u003e\n    \u003csecond\u003e\n      \u003cthird /\u003e\n    \u003c/second\u003e\n  \u003c/parent\u003e\n);\nsnapshot = await descendants(tree);\nok(name(snapshot[0]) === \"first\");\nok(name(snapshot[1]) === \"second\");\nok(name(snapshot[2]) === \"third\");\n```\n\nAs with `children`, `descendants` to can be accessed through `for await`\n\n```typescript jsx\nfor await (snapshot of descendants(tree)) {\n  ok(name(snapshot[0]) === \"first\");\n  ok(name(snapshot[1]) === \"second\");\n  ok(!snapshot[2] || name(snapshot[2]) === \"third\");\n}\n```\n\n## descendantsSettled\n\nYou may want to be able to observe the resolution state of all descendants, as with `childrenSettled`\n\nFor this you can use the `descendantsSettled` accessor\n\n```typescript jsx\nconst { descendantsSettled } = await import(\"@virtualstate/focus\");\n\ntree = (\n  \u003cparent\u003e\n    \u003cfirst /\u003e\n    \u003csecond\u003e\n      \u003cComponentThrows /\u003e\n    \u003c/second\u003e\n  \u003c/parent\u003e\n);\n\nsnapshot = await descendantsSettled(tree);\nok(snapshot[0].status === \"fulfilled\");\nok(snapshot[1].status === \"fulfilled\");\nok(snapshot[2].status === \"rejected\");\n```\n\n\n\n```typescript jsx\nfor await (snapshot of descendantsSettled(tree)) {\n  ok(snapshot[0].status === \"fulfilled\");\n  ok(snapshot[1].status === \"fulfilled\");\n  ok(!snapshot[2] || snapshot[2].status === \"rejected\");\n}\n```\n\nBecause we can expose a bit more information with `descendantsSettled`, you can also\naccess the parent of an individual status object.\n\nThis is helpful when re-creating a tree from these descendants, or creating associations between them.\n\n```typescript jsx\nsnapshot = await descendantsSettled(tree);\nok(snapshot[1].status === \"fulfilled\");\nok(snapshot[2].parent === snapshot[1].value);\n```\n\nThis can also be accessed using through the `for await` pattern:\n\n```typescript jsx\nfor await (snapshot of descendantsSettled(tree)) {\n  ok(snapshot[1].status === \"fulfilled\");\n  ok(!snapshot[2] || snapshot[2].parent === snapshot[1].value);\n}\n```\n\n## raw\n\nThe value you have access to, returned from the JSX node creation process, may not be the original representation\nused for the JSX node. This original raw representation may be helpful when creating new accessor functions, or\nwhat to inspect source definitions of component functions.\n\nIf there is another representation available, the `raw` accessor can be used to access it, if there\nis no raw representation, then that means the passed node is a raw representation itself, which is returned by default.\n\n```typescript jsx\nconst { raw } = await import(\"@virtualstate/focus\");\n\nnode = \u003cnamed /\u003e;\nrawNode = raw(node);\nok(name(rawNode) === \"named\");\n```\n\n## proxy\n\nTo provide a new interface for a JSX node, or provide a different object completely, while still providing support\nfor the above JSX accessors, the `proxy` function can be used\n\n```typescript jsx\nconst { proxy } = await import(\"@virtualstate/focus\");\n\nnode = \u003cnamed /\u003e;\n\napi = { name };\nproxied = proxy(node, api);\nok(proxied.name === \"named\");\n```\n\n\n\n```typescript jsx\napi = { someAccessorName: name };\nproxied = proxy(node, api);\nok(proxied.someAccessorName === \"named\");\n```\n\nIf a `instance` accessor is provided, then this can be used to provide a new object completely\n\n```typescript jsx\napi = {\n  instance() {\n    return { name: Math.random(), source: Math.random() };\n  },\n};\nproxied = proxy(node, api);\n\nok(typeof proxied.name === \"number\");\nok(typeof proxied.source === \"number\");\nok(name(proxied) === \"named\");\n```\n\nWhen instance is used, `raw` becomes useful:\n\n```typescript jsx\nrawNode = raw(proxied);\nok(name(rawNode) === \"named\");\nok(typeof rawNode.name !== \"number\");\nok(rawNode === raw(node));\n```\n\nIf you need to access the original instance that is being proxied, you can use\nthe `instance` accessor.\n\n```typescript jsx\nconst { instance } = await import(\"@virtualstate/focus\");\n\nstaticInstance = { something: 1 };\napi = {\n  instance() {\n    return staticInstance;\n  },\n};\nproxied = proxy(node, api);\nnodeInstance = instance(proxied);\nok(typeof proxied.something === \"number\");\nok(nodeInstance === staticInstance);\nok(nodeInstance !== proxied);\n```\n\n[//]: # (src/trying-to-write-documentation/accessors-how.tsx)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvirtualstate%2Ffocus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvirtualstate%2Ffocus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvirtualstate%2Ffocus/lists"}