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

z-idx

v1.1.1

Published

z-index DAG builder converting declarative stacking rules into stable numeric layers for shared UI libraries.

Downloads

351

Readme

💤 z-idx

z-index DAG builder converting declarative stacking rules into stable numeric layers for shared UI libraries.

Contents

  1. Getting Started
    1. Installation
    2. Example
    3. Purpose
  2. Rationale
    1. Core Concepts
    2. Type Inference
    3. API Surface
  1. Pair Catalogue
    1. Pair Basics
    2. Pair Recursion
    3. Pair Inference
  2. Topology Atlas
    1. Three Nodes
    2. Four Nodes
    3. Five Nodes
  1. Extensions
    1. Extension Stability
    2. Extension Density
    3. Extension Packing
  2. Appendix
    1. Design Notes
    2. Contributing
    3. License

Getting Started

Installation

npm i z-idx

Example

const base = index((z) => z('primary overlay', ['primary modal', 'Github']), { step: 1 })
const next = base((z) => z('primary modal', 'secondary overlay', 'secondary modal'))

if (base.Github !== next.Github) throw Error()

render(<MenuPlayground next={next} />)

Purpose

z-idx turns declarative partial-order z-relations into numeric stacking ranks that stay stable when extended. It accepts linear chains, parent-to-children trees, and nested pairs, lifting all key names into TypeScript inference so downstream packages share identical numbers even after override phases.

Rationale

Core Concepts

A z-idx build receives a helper z. Passing multiple strings like z('a','b','c') emits ordered pairs a<b<c with uniform stride. Passing a parent and an array such as z('a',['b','c','d']) links the parent below each child while placing siblings at the same rank. Nested arrays or previously returned Edge can be embedded, enabling tree-shaped DAGs without losing ordering. Ranks start at START (1<<10) with stride STEP (1<<10) so later inserts can bisect gaps without moving seeded nodes. A topological pass (Kahn) rejects cycles; a second pass computes lower and upper bounds per node.

Type Inference

z-idx returns an object that is both callable and map-like. Every key encountered during build is captured in the return type, allowing editors to suggest properties (base.a, base.b) and to hint previous keys during extension (base((z)=>[z('b','x','c')])). Edges preserve their embedded key set even when nested inside arrays, so deeply composed trees still surface full autocomplete.

API Surface

(build: (z: ZFun) => P): ZApi<Keys<P>>

ZFun supports two shapes. Linear form: z(lower, mid, upper, ...) creates consecutive relations. Tree form: z(parent, childrenArray) where childrenArray may contain strings, nested arrays, or Edge; siblings in an array share the same rank. Returned ZApi is callable for extension and exposes numeric ranks keyed by name.

Pair Catalogue

Pair Basics

Deterministic stride across linear chains: z('a','b','c','d') yields ascending ranks with constant gap. Parent-array flattening: z('a',['b','c','d']) keeps a below each child and places siblings at the same rank. Mixed declarations co-exist: a chain plus subtree (z('a','b','c'), z('b',['d','e'])) still keeps a uniform step. Deeply nested arrays collapse into one level above the parent while preserving sibling rank equality. Composite inference confirms all keys {a,b,c,d,e} appear numerically typed.

Pair Recursion

Edge can be reused as children. Building z('a',[z('b','c','d'),'e']) links a below the chain b<c<d and also below the sibling e. Multiple tagged subtrees under one parent share the parent as lower bound and maintain their own internal ordering. Mixed top-level chains with sibling arrays maintain uniform stride while branching at each fork point. Inference spans linear, array, and tagged inputs ensuring the returned shape exposes every node.

Pair Inference

Nested tagged subtrees recurse without losing step: z('a',[z('b',[z('c','d'),'e']), z('f',['g'])]) yields monotone ranks where a sits below both b and f, with b below c<d and e, while f sits below g. Deeply wrapped sibling arrays such as z('a',[['b','c'],['d','e'],'f']) flatten into ordered groups above a where sub-arrays introduce ordering between groups. Extensions that combine chain and tree forms leave seeds untouched while placing new nodes between them; new keys remain greater than their lower bounds and below preserved uppers. Further composition (z('a',['b','c']), z('b',[z('d',['e',z('f','g')]),'h'])) keeps all eight keys ordered and accessible on the returned API.

Topology Atlas

Three Nodes

All six non-isomorphic DAG shapes for three vertices are expressible. Straight chain a<b<c stays sorted. Single-parent sibling array a<[b,c] places both children at the same rank above the parent. Dual roots into one sink (a->c, b->c) converge cleanly. Fully dense triangle (a->b, a->c, b->c) respects transitivity. Nested pair arrays z('a',[z('b','c')]) flatten to the same order. Late-arriving ancestor pairs still yield the canonical topological sequence.

flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
z(['a', 'b', 'c'])
flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
    a --> b
z('a', 'b')
flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
    a --> b
    a --> c
z('a', ['b', 'c'])
flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
    b ---> a
    c ---> a
z(['b', 'c'], 'a')
flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
    a --> b
    b --> c
z('a', 'b', 'c')
flowchart TB
    g[" "]
    a ~~~ g
    g ~~~ b
    g ~~~ c
    style g fill:none,stroke:none,color:none
    a --> b
    b --> c
    a --> c
z('a', 'b', 'c'), z('a', 'c')

Four Nodes

The catalogue of four-vertex DAGs (31 shapes) maps onto builds combining chains, fans, diamonds, ladders, and merged roots. Examples include diamond a->b, a->c, b->d, c->d, balanced forks a->[b,c,d], reversed sibling order a->[d,c,b], cross-braced ladders a->b, a->c, b->c, c->d, parallel roots with tails, and dual roots merging before a sink. Deterministic spacing holds across all enumerated isomorphism classes, with chains producing uniform stride and fan siblings sharing equal rank.

6 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    b --> d
    a --> d
    b --> c
    c --> d
z(['a', 'b'], ['c', 'd']), z('a', 'b'), z('c', 'd')

5 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    b --> d
    a --> b
    a --> d
    a --> c
    b --> c
z(['a', 'b'], ['c', 'd']), z('a', 'b')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> d
    c --> d
    b --> d
    b --> c
z(['a', 'b'], ['c', 'd']), z('c', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> b
    c --> d
    a --> d
    b --> c
z('a', ['b', 'c', 'd']), z('b', 'c', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> d
    a --> c
    b --> d
    c --> d
z('a', ['b', 'c'], 'd'), z('a', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> b
    b --> c
    c --> d
    b --> d
z('a', ['b', 'c'], 'd'), z('b', 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> d
    b --> c
    b --> d
    c --> d
z('a', 'b', ['c', 'd']), z(['a', 'c'], 'd')

4 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    b --> d
    a --> d
    b --> c
z(['a', 'b'], ['c', 'd'])
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    a --> d
    b --> c
z('a', ['b', 'c', 'd']), z('b', 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    b --> c
    b --> d
z('a', ['b', 'c']), z('b', ['c', 'd'])
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    b --> c
    c --> d
z('a', 'b', 'c', 'd'), z('a', 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> d
    b --> c
    c --> d
z('a', 'b', 'c', 'd'), z('a', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> d
    b --> c
    c --> d
z(['a', 'b'], 'c', 'd'), z('a', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    b --> d
    c --> d
z('a', ['b', 'c'], 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> d
    b --> d
    c --> d
z('a', ['c', 'd']), z(['b', 'c'], 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    b --> c
    b --> d
    c --> d
z('a', 'b', 'c', 'd'), z('b', 'd')

3 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    a --> d
z('a', ['b', 'c', 'd'])
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
    b --> c
z('a', ['b', 'c']), z('b', 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    a --> d
    b --> c
z(['a', 'b'], 'c'), z('a', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    b --> c
    b --> d
z('a', 'b', ['c', 'd'])
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    b --> c
    c --> d
z('a', 'b', 'c', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    b --> c
    c --> d
z(['a', 'b'], 'c', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> d
    b --> c
    c --> d
z('a', 'd'), z('b', 'c', 'd')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> d
    b --> d
    c --> d
z(['a', 'b', 'c'], 'd')

2 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    b --> c
z('a', 'b', 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    a --> c
z('a', ['b', 'c'])
flowchart LR
    subgraph x[" "]
        direction TB
        a
        b
    end
    subgraph y[" "]
        direction TB
        c
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> c
    b --> c
z(['a', 'b'], 'c')
flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
    c --> d
z('a', 'b'), z('c', 'd')

1 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
    a --> b
z('a', 'b')

0 edges

flowchart LR
    subgraph x[" "]
        direction TB
        a
        c
    end
    subgraph y[" "]
        direction TB
        b
        d
    end
    a ~~~ b
    c ~~~ d
    style x fill:none,stroke:none
    style y fill:none,stroke:none
z(['a', 'b', 'c', 'd'])

Five Nodes

Five-vertex coverage extends chains, wide fans, multi-source funnels, diamonds with tails, interleaved ladders, balanced two-level trees, partial fans with extended child, mid-node splits, and diamonds with head. Each construction confirms sorted order, equal stride between consecutive nodes in the topological sequence, and stable root-to-leaf monotonicity even as edges multiply. The tests validate that every key participates in the final ordering and that no hidden permutations violate declared constraints.

flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    b --> c
    c --> d
    d --> e
z('a', 'b', 'c', 'd', 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    a --> c
    a --> d
    a --> e
z('a', ['b', 'c', 'd', 'e'])
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> e
    b --> e
    c --> e
    d --> e
z(['a', 'b', 'c', 'd'], 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    a --> c
    b --> d
    c --> d
    d --> e
z('a', ['b', 'c'], 'd', 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    b --> e
    a --> c
    c --> d
    d --> e
z('a', 'b', 'e'), z('a', 'c', 'd', 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    a --> c
    b --> d
    c --> e
z('a', 'b', 'd'), z('a', 'c', 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    a --> c
    a --> d
    d --> e
z('a', ['b', 'c', 'd']), z('d', 'e')
flowchart LR
    g[" "]
    g ~~~ a
    g ~~~ b
    g ~~~ c
    g ~~~ d
    g ~~~ e
    style g fill:none,stroke:none,color:none
    a --> b
    b --> c
    b --> d
    c --> e
    d --> e
z('a', 'b', ['c', 'd'], 'e')

Extensions

Extension Stability

First builds are reproducible: identical inputs yield identical ranks. Extending with additional relations preserves all seeded values while inserting newcomers at midpoints between valid bounds (d = mid(a+1, b-1)). Multiple extensions chained in different regions keep earlier inserts fixed, showing that rank assignment uses seeds as immutable fences. When nested tree shorthand seeds wide gaps, subsequent inserts between siblings respect original positions and narrow gaps symmetrically.

Extension Density

Iterative midpoint insertions demonstrate gap shrinkage. Starting from a<b, successive overrides insert c, then d, then e, then f, each halving or quartering the remaining interval. Earlier inserts remain unchanged (c stays at the first midpoint) while new points land strictly inside ever smaller windows. Inserts can target both sides of a midpoint or only the right side; ordering remains intact and seeds never drift.

Extension Packing

Extensions also work outside the initial segment: placing nodes above the highest seed uses STEP-sized spacing, while placing nodes below the lowest seed uses dyadic interval subdivision. Dense clusters near a large gap center keep seeds stable. Mixing outer inserts with inner midpoints leaves fences intact while layering additional nodes between existing seeds. Packed sibling gaps across multiple regions show that each local interval can be subdivided independently across successive overrides, with later splits narrower than the prior interval. Cycles throw an exception immediately, ensuring the DAG assumption holds even in extension calls.

Appendix

Design Notes

Implementation relies on Kahn topological sorting over all declared pairs plus seeded extras, followed by forward and backward constraint propagation through parent-child edges to derive lower and upper fences. A constant STEP of 1024 defines initial gaps; the dyadic function (1 << (31 - clz32(n))) subdivides intervals during insertion cascades by selecting the largest power-of-two that fits within the available span. Fence propagation walks the DAG forward for lower bounds and backward for upper bounds, keeping determinism across runs.

Contributing

Contributions should mirror the existing Vitest suites: pair basics, recursion, inference, topology (three through five nodes), extension stability, density, and packing. Each scenario should validate ordering, stride constancy, and seed preservation without relying on external fixtures.

License

MIT