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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xenosystem/tree-core

v0.1.0

Published

The source-agnostic tree engine shared by xeno.core.layers and xeno.core.tree — recursive walk, visible-row flatten, range selection, virtualization, and the descendant-drop refusal. Zero dependencies, zero DOM.

Readme

@xenosystem/tree-core

The source-agnostic tree engine shared by xeno.core.layers and xeno.core.tree. The shared thing is the walk, not the panel.

Zero dependencies. Zero DOM. Zero React.

Why this package exists

Two reasons, both of them bugs that are on screen right now:

1. The shallow-walk class is the most-repeated bug in the engineering log — ~9 venues, 5 checklist entries, canonical statement: "any getLayers().map/forEach/some is guilty until it recurses." It has silently dropped grouped nodes in export, PSD write, detection, load and crash recovery. Two independent recursive walkers — one in Layers, one in Tree — is exactly how it recurs a tenth time.

2. 🔴 Reparent-into-own-descendant silently deletes the subtree, live in two shipping apps. xeno-3d/.../stores/sceneStore.ts:2851 and xeno-engine/.../stores/engineStore.ts:1745 both reparent by detach-then-reattach. When the drop target is a descendant of the dragged node, the target is gone from the remainder after the detach, the insert is a silent no-op, and the node plus its entire subtree disappears — with an undo entry already pushed, labelled "Reparent Object", so Ctrl+Z restores nothing. The only guard either has is id === newParentId, which catches dropping a node onto itself and nothing else.

resolveDropTarget refuses that drop, with a reason, and it lives here rather than in a host bridge so no adopting host can forget it.

What is in it

| Module | Exports | |---|---| | tree | walkTree · allIds · collectDescendants · getAncestors · isAncestorOf · displayOrder · flattenVisible · matchesFilter · rowIndexOf · rangeBetween | | virtualize | computeWindow · scrollToIndex | | dropZone | resolveDropTarget | | throttle | createThrottle |

How it is generalized

Layers and Tree carry different node shapes — name vs label, storage order vs document order, different capability vocabularies. Rather than force one shape on both, every function is generic over a structural minimum and takes the shape-specific decisions as explicit accessors:

interface TreeNodeLike { id: string; parentId?: string | null; children?: readonly string[] }
interface TreeLike<N>  { nodes: Record<string, N>; rootIds: readonly string[]; order?: 'bottom-first' | 'top-first' }
flattenVisible(tree, {
  collapsed,
  filter: 'shadow',
  labelOf: (n) => n.label,          // `name` in Layers, `label` in Tree
  isContainer: (n) => n.kind === 'folder' || Array.isArray(n.children),
})

Both panels bind their accessors once and re-export the signatures they always had.

Two deliberate defaults:

  • order absent ⇒ top-first. Document order is the common case; only stacking surfaces (Pixel, Canvas) store bottom-first, and those declare it. The flag is honoured, never guessed — guessing is how a layer stack renders upside down.
  • labelOf absent ⇒ ''. A caller that forgets it filters everything out rather than silently matching on a guessed field. Loud beats convenient.

children presence is load-bearing

children: [] is an empty container. children: undefined is a leaf. They render differently (a twisty vs none) and they behave differently on drop. Nothing in this package collapses the distinction, and isContainer is overridable precisely because an async source has a third case — a container whose children are not loaded yet.

Scripts

npm run typecheck   # tsc --noEmit
npm test            # vitest run   (51 tests)
npm run build       # tsup → dist (esm + cjs + d.ts)

Consumers

| Package | Uses | |---|---| | @xenosystem/panel-layers | Binds name + its cap vocabulary; re-exports every signature unchanged (the extraction was non-breaking — its 109 tests pass untouched). | | @xenosystem/panel-tree | Binds label + async-aware isContainer, adds per-node child state on top. |

A host bridge should import from here too. The review gate is unchanged and applies upstream of the panel: every walk recurses.