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

@io-gui/navigation

v2.0.0-alpha.3

Published

A set of navigators for Io-Gui.

Readme

@io-gui/navigation

Navigation and content selection components for Io-Gui.

See live examples here

Overview

IoNavigator
├── IoMenuOptions | IoMenuTree (navigation menu)
└── IoSelector (content display)
    └── selected element from elements[]

IoCollapsible
└── IoBoolean (toggle)
└── elements[] (collapsible content)

Elements

IoNavigator

Full navigation component combining menu and content selector.

type IoNavigatorProps = {
  option: MenuOption            // Navigation options
  elements: VDOMElement[]       // Content elements matched by id
  menu?: 'top' | 'left' | 'right'  // Menu position
  depth?: number                // Menu expansion depth
  select?: 'shallow' | 'deep' | 'all' | 'none'
  caching?: 'proactive' | 'reactive' | 'none'
  anchor?: string               // Scroll anchor
  widget?: VDOMElement          // Custom menu widget
}

Menu positions: | Position | Layout | Menu Type | |----------|--------|-----------| | top | Column | IoMenuOptions (horizontal) | | left | Row | IoMenuTree | | right | Row | IoMenuTree |

Selection modes: | Mode | Behavior | |------|----------| | shallow | Shows selectedIDImmediate (direct child) | | deep | Shows final selectedID in tree | | all | Shows all elements (*) | | none | Shows nothing |

Usage:

new IoNavigator({
  menu: 'left',
  option: new MenuOption({
    mode: 'select',
    options: [
      { id: 'Home', selected: true },
      { id: 'About' },
      { id: 'Contact' },
    ]
  }),
  elements: [
    div({ id: 'Home' }, 'Home content'),
    div({ id: 'About' }, 'About content'),
    div({ id: 'Contact' }, 'Contact content'),
  ]
})

IoSelector

Content switcher that displays elements based on selection.

type IoSelectorProps = {
  elements: VDOMElement[]     // Available content elements
  selected: string            // Element id to display, or '*' for all
  anchor?: string             // Scroll-to anchor
  caching?: 'proactive' | 'reactive' | 'none'
  loading?: boolean           // Shows loading spinner
}

Caching modes: | Mode | Description | |------|-------------| | proactive | Pre-renders all elements in background | | reactive | Caches elements after first render | | none | Re-renders element each time selected |

Key behaviors:

  • Matches elements by id property
  • Supports dynamic imports via import property on elements
  • Scroll-to-anchor with debounced sync

Dynamic Imports

Elements can specify an import path for lazy loading:

ioSelector({
  selected: 'heavy-page',
  elements: [
    div({ id: 'light-page' }, 'Immediate content'),
    div({ 
      id: 'heavy-page',
      import: './pages/heavy-page.js'  // Loaded on demand
    }),
  ]
})

Loading flow:

  1. Shows loading spinner
  2. Dynamically imports module
  3. Renders element
  4. Resumes proactive caching (if enabled)

Anchor Navigation

IoSelector syncs with anchor property for deep linking:

// URL: #section-2
ioSelector({
  anchor: this.bind('anchor'),
  elements: [...]
})

// Scrolls to element with data-heading="section-2"

Behaviors:

  • Changes to anchor scroll to matching [data-heading] element
  • Scroll events update anchor to nearest heading
  • 120ms debounce prevents scroll/anchor update loops

IoCollapsible

Expandable content container with toggle header.

type IoCollapsibleProps = {
  label: string
  icon?: string
  expanded?: boolean
  elements: VDOMElement[]
  direction?: 'column' | 'row'
}

Key behaviors:

  • Toggle via click on header or Enter/Space
  • Content only rendered when expanded
  • Direction controls flex layout of content

Usage:

ioCollapsible({
  label: 'Advanced Settings',
  expanded: false,
  elements: [
    ioNumber({ label: 'Option 1', value: 0 }),
    ioNumber({ label: 'Option 2', value: 0 }),
  ]
})

Data Flow

MenuOption selection changes
    ↓
IoNavigator.optionMutated()
    ↓
Determines selected id based on 'select' mode
    ↓
IoSelector.selectedChanged()
    ↓
If caching: check cache for element
If import: load module first
    ↓
Render element to DOM
    ↓
If anchor: scroll to heading

Events

| Event | Dispatched By | Payload | Purpose | |-------|---------------|---------|---------| | scroll | IoSelector | - | Scroll position changed |

Edge Cases

Cache Collision

If IoSelector is reused in different templates with colliding element IDs, cached elements may incorrectly persist. Use unique IDs across the application.

Proactive Caching Timing

Proactive caching happens during idle frames to avoid blocking. If many elements have dynamic imports, initial caching may take several seconds.

Scroll Suspension

When programmatically changing anchor, scroll events are temporarily suppressed (120ms) to prevent feedback loops. Similarly, when scrolling updates anchor, programmatic scroll-to is suspended.

Element Disposal

Cached elements not in the DOM are properly disposed when IoSelector is disposed, preventing memory leaks.