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

@pihanga/core

v0.8.1

Published

Core module of the Pihanga framework

Readme

Pihanga - Framework for dynamically extendible React apps

pihanga (noun) window, sliding slab of the traditional window of a wharenui.

Motivation

Most of the web frontends we are usually building are for a rather small user base to better use or maintain rather complex backends. Many of those systems start out small but over time expand in various directions by different teams using different technologies. Most likely a common scenario for many business support services.

We use micro services and similar technologies to avoid any unnecessary dependencies in the backend, but our users, understandably want a unified UX in the frontend.

This project is an attempt to achieve that while supporting the independent development of the various parts and components surfacing specific backend capabilites. In other words, we want to minimize the amount of code changes when adding new functionality while still supporting an integrated UX experience.

Let me explain that with a trivial example. Let us assume we just delivered an internal car booking service for a company. After a successful launch a different part of the business in charge of managing the truck fleet wants to add their service to it, as well. Their backend is very different and the original frontend team has already been dissolved. We want to make it easy for the "truck" team to independently develop the truck specific UX components as well as extension points to existing generic functionality, such as search, without needing to modify the car components. Frontend integration should be as simple as adding an additional script link to the index page.

Approach

We have found the React/Redux approach to be extremely useful in managing dependencies between UX components and cleanly separating state synchronisation between front- and backend. In addition, a purely functional approach to component design not only leads to much cleaner code, but also simplifies testing considerably.

With the positive lessons learned from defining a web page as pure functions over a single state structure, we wanted to see if we can push this further and essentially select those functions through another function over a UX state object.

Basic Idea

In order to do that, we need to define a construction model for a web page. In Pihanga, like in other frameworks, a page is composed of hierarchically nested cards. Or, in other words, a tree of cards with the root of the tree being the entire page frame. Each card can contain normal web components as well as other cards. However, we restrict a card to define an embedded card only by a tree-globally unique name. In addition, each card is stateless and it's final presentation and behaviour defined by a set of externally provided properties (which may include the name to be assigned to an embedded card).

The Pihanga state structure, different to the Redux state tree, is a map between the name of a card and it's associated property list. However, the values in that property list can be queries (currently functions) over the entire Pihanga state (all other cards) and the Redux state.

Let's demonstrate that on a simple app consisting of a frame-filling page card which will show one of two listing cards depending on the route.routePath property in the Redux state.

The Pihanga state structure is defined as follows:

import flow from 'lodash.flow';
import { pQuery } from '@pihanga/core'card.service';

export default {
  page: {
    cardType: 'AppPage',
    title: 'Transportation Service',
    contentCard: flow(
        pQuery(null, 'path', (s) => s.route.routePath),
        (a) => a.length == 1 ? a[0].cardName : 'carListing'
    ),
    //...
  },
  carListing: {
    cardType: 'Table',
    title: 'Cars',
    path: '/cars',
    //...
  },
  truckListing: {
    cardType: 'Table',
    title: 'Trucks',
    path: '/trucks',
    //...
  },
}

and the AppPage card is implemented as follows:

import { Card } from '@pihanga/core';

export const AppPageCard = ({
  title,
  contentCard, 
  //...
}) => {
  return (
    <div>
      ...
        <Card cardName={contentCard} />
      ...
    </div>
  );
};

The contentCard property in the page card definition shows the use of query to dynamically calculate the property value. pQuery returns an query over the Pihanga state. pQuery(null, 'path', (s) => s.route.routePath) selects all card defintions (null wildcard) where the path property (if defined) is equal to the current Redux value route.routePath. For the current setup, the query will return zero or one records which is reduced in the second function to flow either the name of the single matching card or a default card.