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

@tamer4lynx/tamer-navigation

v0.0.1

Published

Native navigation elements for Lynx — zero-bitmap transitions (slide, fade, modal) via live FrameLayout/UIView stacks.

Readme

@tamer4lynx/tamer-navigation

Framework-agnostic native navigation transport for Tamer/Lynx:

  • TamerNav (push / pop / popAll / dispatch / update) backed by NativeModules.TamerNavModule
  • Global events on the root LynxView: tamer-nav:dispatch, tamer-nav:popped, tamer-nav:transition-end
  • readHydratedStateJson / subscribeHydratedStateJson and TAMER_NAV_STATE_PROP for coordinator snapshots

Stack UIs should use native spokes (see @tamer4lynx/tamer-router FileRouter) or your own coordinator on top of this transport.

Choosing a coordinator approach

With @tamer4lynx/tamer-router (recommended): FileRouter handles push/pop wiring, file-based route generation, back gestures, and cross-spoke state bridging. Most apps should use this.

Without tamer-router (manual coordinator): Call TamerNav.push/pop/dispatch/update directly. Listen to tamer-nav:dispatch and tamer-nav:popped global events on the coordinator LynxView and maintain your own route stack. BackHandlerProvider + useBackHandler from @tamer4lynx/tamer-router handle back gestures without the full file router. See packages/example/src/example_stack.tsx for a complete working reference of this pattern.

LynxGroup / LynxViewGroup (required for stack spokes)

TamerNav’s coordinator and stack spoke LynxViews must share one Lynx LynxGroup instance with the root LynxView. They should also use a persistent LynxViewGroup scoped by bundle URL so native template fetches stay tied to the correct source while module singletons remain in the shared runtime group.

  • Android: Before TamerNavHost.attachRoot, configure the root builder with a shared LynxGroup and a persistent ILynxViewGroup for its bundle URL. Set TamerNavHost.sourceSpokeBuilder so every spoke receives its src, resolves the matching view group, and uses the same LynxGroup reference (see tamer-dev-app / tamer-host templates).
  • iOS: Set builder.group and builder.lynxViewGroup on the root LynxView builder from a shared runtime helper. Set TamerNavHost.configureSpokeBuilder so each spoke receives its src and resolves the matching LynxViewGroup.
  • TamerNavHost.attachRoot fails fast (Android and iOS) if the root has no group.

Engine caveat: Lynx’s Android LynxGroup API documents non–single-group IDs as experimental; TamerNav still requires a shared group for this design—treat engine behavior as a known risk.

React: A shared JS context group does not guarantee a single React reconciler or shared React Context across multiple LynxViews; validate app-level assumptions yourself.

State continuity

Important — Lynx engine constraint. A shared LynxGroup (even with setEnableJSGroupThread(true)) and a per-URL LynxViewGroup share the JS thread and template parsing, but not the JS heap / VM context. Each LynxView instance receives a fresh JavaScript context, so module-level singletons (zustand create(...), redux createStore, plain let store = ...) are re-evaluated per spoke.

This is a property of the upstream Lynx runtime. Audited surfaces: LynxGroup/LynxGroupBuilder, LynxRuntimeOptions, LynxBackgroundRuntimeOptions, LynxViewBuilder, iOS LynxGroupOption, setBoolConfig/setStringConfig keys, ILynxViewRuntimeCacheManager, and getSharedModuleFactory. None expose cross-view JS heap pooling. Patching the Lynx engine (core/runtime/js/) would be required to expose it.

To verify in your build, enable the diagnostic logs shipped with the host/dev-client templates:

  • Android: adb logcat -s TamerHeap — root and spoke print matching group= and viewGroup= identities.
  • iOS: filter Xcode console for [TamerHeap].
  • App: a console.log('[TamerHeap] ... module-eval', Math.random()) at module top of any singleton store will print once per spoke whenever isolation kicks in.

If identities match but the JS marker prints per-spoke, you are hitting the engine constraint above.

Working today

  • React-tree state inside a single LynxView (Context, useState, etc.) — works as normal.
  • Pass-through props on TamerNav.push({ initData, globalProps }) — survives navigation since native carries the JSON.

Cross-spoke singleton continuity

Use TamerStateSyncProvider + createTamerStateSync from @tamer4lynx/tamer-router. This is an explicit native-bridge sync that mirrors a JSON snapshot of a store across spokes:

import { create } from 'zustand'
import { createTamerStateSync, TamerStateSyncProvider } from '@tamer4lynx/tamer-router'

export const useDemoStore = create<DemoState>(...)

const demoSync = createTamerStateSync('demo-store', {
  getState: () => useDemoStore.getState(),
  subscribe: (listener) => useDemoStore.subscribe(listener),
  hydrate: (json) => useDemoStore.setState(JSON.parse(json)),
})

// Wrap the FileRouter root once per LynxView entry:
<TamerStateSyncProvider syncs={[demoSync]}>{...}</TamerStateSyncProvider>
// `providers` is a deprecated alias for `syncs`; prefer `syncs`.

The same sync object goes in every entry that needs to read/write the store. Bridge cost is one JSON round-trip per setState.

Native transition end

After stack push/pop animations finish, the host emits tamer-nav:transition-end on the coordinator LynxView with { screenId, animated }. screenId is the top spoke; it is empty when the stack is cleared (coordinator only). Use subscribeTamerNavTransitionEnd from this package, or useLynxGlobalEventListener(TAMER_NAV_TRANSITION_END_EVENT, …), to defer heavy UI without coupling to the router.

Android emits after each spoke enter animation ends (onCreateAnimation). When the last spoke is removed there is no enter animation on the coordinator; the package emits after a 280ms delay so it stays aligned with the XML transition duration. iOS uses UINavigationControllerDelegate.navigationController(_:didShow:animated:).

Spoke shell color (globalProps.contentBackgroundColor)

Before the spoke Lynx bundle paints, native containers can flash the wrong color. Pass contentBackgroundColor on TamerNav.pushglobalProps as a hex string (#RRGGBB or #AARRGGBB). Android/iOS read this key and tint the fragment/VC root and LynxView; if missing, they fall back to the platform theme background (colorBackground / UIColor.systemBackground), not pure black.

@tamer4lynx/tamer-router FileRouter merges theme.background into globalProps for coordinator native pushes when theme colors are available.

<overlay> (unchanged)

The overlay element remains for dialogs and similar UI. See native sources under overlay/ and TamerNavPageOverlay.