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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@gisatcz/ptr-router

v0.3.0

Published

Panther router

Downloads

30

Readme

.github/workflows/test.yml

ptr-router

Api

Router

/**
 * @param {Object} options
 * @param {Object} options.routes Keys are paths in format `/path/:param`, values are route data
 *     (object with key 'name' or string)
 * @param {Function=} options.onChange Function accepting request called when route is matched.
 *     Default `onChange` function calls `handler(request)` where `handler` is taken from route data.
 * @param {Function=} options.notFoundHandler Function accepting request called when no route is matched
 * @param {Function=} options.navHandler Function called instead of `nav` and `redirect` (useful for SSR)
 * @param {string=} options.currentUrl Useful when doing SSR
 * @param {store=} options.store Redux store to which current page will be stored
 * @param {Object=} options.generateUrlsOptions Options with params for generateUrls https://github.com/kriasoft/universal-router/blob/main/docs/api.md#url-generation
 *
 * Request is map with optional keys:
 * - `match`
 *   - matched route. It is object with keys `data` (route data object), `pathParams`
 * - `context`
 *   - Current UniversalRouter context with actual url, parameters, routes...
 * - `queryString`
 */
create({
	routes,
	onChange,
	notFoundHandler,
	currentUrl,
	navHandler,
	store,
    generateUrlsOptions,
});

Methods of router created using create above

nav(url)

Opens url, which triggers onChange or notFoundHandler.

redirect(url)

Same as nav(url), except previous url in history is replaced with the one provided.

refresh()

Triggers onChange or notFoundHandler.

pathFor(page, params)

Generates url based on route name (page) and path params.

destroy()

Destroys router. Useful in tests to remove listeners from DOM.

Redux integration (optional)

This library provides functions that can be used to store/retrieve current page from Redux store.

/**
 * Redux action storing page name with params into store.
 * `name` should be taken from route name.
 */
changePage(name, params);

/**
 * Redux selector retrieving page and action from store.
 */
pageSelector(state, basePath);

/**
 * Redux reducer.
 */
reducer(state = null, action);

Demo

import * as ptrRouter from '@gisatcz/ptr-router';

const routes = {
    '': 'homepage',
    '/hello/:name': {
        name: 'hello',
        handler: request => {
            // show alert when route is matched
            alert(`Hello ${request.match.pathParams.name}!`);
        }
    },
    '/fruit': {
        name: 'fruit',
        handler: request => {
            if(request.context.pathname === '/fruit') {
                alert(`Hello I'm on fruite url!`);
            } else {
                // pass to the children
                request.context.next();
            }
        },
        children: {
            'apple': {
                name: 'fruit:apple',
                handler: request => {
                    // show alert when route is matched
                    alert(`Hello ${request.match.pathParams.name} ${request.context.pathname}!`);
                }
            }
        }
    }
};

function notFoundHandler(request) {
    console.error(`No route matched url ${location.href}`);
}

function init({navHandler, currentUrl}) {
    const generateUrlsOptions = {
        stringifyQueryParams: (params) => new URLSearchParams(params).toString() //parse unknown params to the querystring
    }
    const router = ptrRouter.create({routes, notFoundHandler, navHandler, currentUrl, generateUrlsOptions});
    const helloUrl = router.pathFor('hello', {name: 'John', address: 'prague'}; // => /hello/John?address=prague
    router.nav(helloUrl); // opens page `/hello/John` that shows alert `Hello John!`
    router.nav('/some-random-url'); // `notFoundHandler` logs error into the console
}

Initialization in browser

init();

Initialization on server

function handler(req, res) {
    let requiredUrl = req.url; // what url we will want to render?

    // replaces navigation handlers in router by changing the local `requiredUrl`
    const navHandler = (url) => {
        requiredUrl = url;
    };

    init({currentUrl: req.url, navHandler});

    if (requiredUrl != req.url) {
        // if url changed during initialization above, redirect to the required url
        res.redirect(301, requiredUrl);
        return;
    }

    // ...
}

Demo with redux

import * as ptrRouter from '@gisatcz/ptr-router';
import {createStore, combineReducers} from 'redux';

const ROUTER_PATH = 'router';

const store = createStore(
    combineReducers({[ROUTER_PATH]: ptrRouter.reducer}),
    {}
);

// page selector used by application with router path in state already filled in
const pageSelector = state => ptrRouter.pageSelector(state, ROUTER_PATH);

const routes = {
    '': 'homepage',
    '/hello/:name': {
        name: 'hello',
        handler: request => {
            // show alert when route is matched
            alert(`Hello ${request.match.pathParams.name}!`);
        }
    }
};

const router = ptrRouter.create({routes, onChange, store});
const helloUrl = router.pathFor('hello', {name: 'John'}; // => /hello/John
router.nav(helloUrl); // opens page `/hello/John` that shows alert `Hello John!`
console.log(pageSelector(tore.getState())); // logs: {name: 'hello', params: {path: {name: 'John'}}}