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

nudgekit

v0.1.0

Published

React Native / Expo bindings for NudgeKit — contextual tips, feature discovery, and onboarding nudges. Pure TypeScript engine + managers + UI, parity-tested with Kotlin NudgeKit 1.0.0.

Readme

nudgekit

React Native / Expo bindings for NudgeKit — contextual tips, feature discovery, and onboarding nudges.

The React Native / Expo package for NudgeKit — the TypeScript rule engine, headless managers + persistence, and the React Native UI layer (provider, hook, pure + managed components), proven behaviourally identical to Kotlin NudgeKit 1.0.0 via shared rule vectors (spec/rule-vectors/). Pure JS/TS, Expo Go-friendly, no native modules — so no Expo config plugin is required. Components are minimal and styleable; animations / popover physics are deferred.

Published as the unscoped npm package nudgekit, first release 0.1.0. react and react-native are peer dependencies (provided by your app); this package does not bundle them.

Part of the same NudgeKit product/brand as the native Android (Kotlin/Compose) library — which is a separate Maven/Gradle distribution, not this npm package.

Install

npm install nudgekit
# peer deps your app already has:
npm install react react-native
  • Expo / Expo Go compatible — pure JS/TS, no native modules, so no Expo config plugin is required.
  • @react-native-async-storage/async-storage is optional — only needed if you use createPersistentTipManager. It is a dependency of the example app, not of this package.
  • The native Android (Kotlin/Compose) NudgeKit is the same product but a separate Maven/Gradle distribution — not this npm package.

What's here

Engine (Phase 1)

  • Tip, TipRule, TipState, TipCounters, TipContext
  • Rules.* builders (same validation as Kotlin)
  • TipDecision, TipHideReason
  • evaluate, shouldShow, select, selectEligible, TipSelection

Managers + persistence (Phase 2)

  • TipManager, ReactiveTipManager
  • MemoryTipManager — in-memory, synchronous reads, subscribe / getSnapshot (useSyncExternalStore-ready)
  • TipStorage, MemoryStorage
  • PersistentTipManager / createPersistentTipManager(storage) — write-through persistence
  • TipAnalytics, NoOpTipAnalytics

React Native UI (Phase 3)

  • NudgeKitProvider — supplies the manager (+ optional analytics) via context
  • useManagedTip(tip) — headless controller (visible, markShown, dismiss, actionPress, decision)
  • InlineTip, TipBox — pure, styleable components (caller controls visibility)
  • ManagedInlineTip, ManagedTipBox — state-aware: render on eligibility, mark shown once per appearance, persist dismissals, fire analytics
import { Rules, MemoryTipManager, type Tip } from 'nudgekit';

const promo: Tip = {
  id: 'promo', title: 'Sale', message: '20% off', priority: 5, groupId: 'home',
  rules: [Rules.notDismissed(), Rules.expiresAfter(7 * 24 * 60 * 60 * 1000)],
};

const manager = new MemoryTipManager();
manager.markShown('promo');              // displayCount++, stamps first/last-shown
const visible = manager.shouldShow(promo);
const winner = manager.selectEligible([promo /* … */]);

Persistence (Expo-friendly, no native module)

TipStorage matches the @react-native-async-storage/async-storage API, so you can pass an AsyncStorage instance directly — but it's optional. MemoryTipManager needs no storage, and MemoryStorage works in Expo Go.

import { createPersistentTipManager, MemoryStorage } from 'nudgekit';

// Tests / Expo Go:
const manager = await createPersistentTipManager(new MemoryStorage());

// Production (only if you already use AsyncStorage — not a hard dependency):
// import AsyncStorage from '@react-native-async-storage/async-storage';
// const manager = await createPersistentTipManager(AsyncStorage);

UI (managed components)

import {
  NudgeKitProvider, ManagedInlineTip, ManagedTipBox, MemoryTipManager,
} from 'nudgekit';

const manager = new MemoryTipManager(); // or await createPersistentTipManager(storage)

function App() {
  return (
    <NudgeKitProvider manager={manager} /* analytics={myAnalytics} */>
      {/* Renders only when eligible; marks shown once; persists dismissal. */}
      <ManagedInlineTip tip={promo} onActionPress={openSale} />

      <ManagedTipBox tip={hint} position="bottom">
        <MyButton />{/* anchor always renders */}
      </ManagedTipBox>
    </NudgeKitProvider>
  );
}

Need full control? Use the pure InlineTip / TipBox and drive visibility yourself, or call useManagedTip(tip) for { visible, markShown, dismiss, actionPress, decision }.

Develop

npm install        # uses .npmrc (legacy-peer-deps); RN is a peer dep, not installed here
npm run typecheck
npm test           # Jest: engine + manager + UI (react-test-renderer)
npm run build      # tsc → lib/ (CJS + .d.ts); what npm publish would ship
npm pack --dry-run # inspect the would-be tarball (lib/ only, no junk)

Parity is enforced against ../../spec/rule-vectors/ — the same fixtures the Kotlin ParityVectorTest (engine) and ParityStateVectorTest (managers) run.

Build & packaging

  • npm run build runs tsc -p tsconfig.build.json, emitting CommonJS + type declarations to lib/ (mainlib/index.js, typeslib/index.d.ts).
  • files ships only lib/; prepare builds automatically on install/publish; prepublishOnly re-runs clean + build + typecheck + tests before any publish.
  • sideEffects: false (tree-shaking-friendly), publishConfig.access: public.
  • Published as the unscoped public package nudgekit (private: false).

Example app

A runnable Expo app lives in example/ and exercises every feature (provider, managed components, the selector, analytics, track/reset). It consumes the library straight from ../src via Metro — see its README to run it.

Releasing (maintainers)

Publishing is manual and gated — there is intentionally no auto-publish CI workflow, and no npm token is stored in the repo. The package is published as the unscoped public package nudgekit:

  1. npm login locally (account abdullajon1991); confirm with npm whoami.
  2. Dry run: npm publish --dry-run (inspect tarball = README + lib/ only).
  3. Publish: npm publish (runs prepublishOnly: clean → build → typecheck → test).
  4. Tag the release and push it.
  5. (Optional, later) add provenance via a GitHub Actions release workflow using OIDC + npm publish --provenance — only after the first manual publish.

Do not paste npm tokens anywhere in the repo or chat; npm login handles auth locally.