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

raid-navigator

v4.1.0

Published

Navigation stack hooked in to a raid signal

Downloads

18

Readme

raid-navigator

Navigation stack hooked in to a raid signal

npm License: MIT Build Status js-standard-style

Documentation

Install

Install with yarn or npm

yarn add raid-navigator
npm i -S raid-navigator

Example

import { render } from 'react-dom'
import { Navigator } from 'raid-navigator'
import { Signal } from 'raid'

const signal = new Signal()

signal.observe(state => {
  render(
    <Navigator signal={signal} navigation={state.navigation}>
      <div route='/'>
        <h1>Index</h1>
      </div>
      <div route='/settings'>
        <h1>Settings</h1>
      </div>
    </Navigator>
    document.querySelector('root')
  )
})

Usage

Raid-navigator controls and selects a set of routes based on the current history state, usually this means selecting a single route but multiple will be rendered if they match. In addition navigator passes the current route state to any matched children.

signal <Signal>

The state raid signal to hook in to. Just pass it in, navigator will do the rest.

navigation <Object>

The current navigation stack, pulled from state.

history

A history implementation to use, this defaults to history/createBrowserHistory but anything that implements the same api would work just fine.

storage

Navigator will try to be smart and store the navigation stack into persistent memory, in order to match its own navigation stack with that of the browser as closely as it can it will attempt to use sessionStorage by default.

Detailed Navigator component api documentation.

Browser history navigator

By default navigator will attempt to use browser memory to manage its stack, this includes storing the navigation state to sessionStorage.

To get started include raid and set up a signal. raid-navigator exposes an initial state that can be added to the signal but its unnecessary as the navigator component will sort it out when it mounts.

This example can all be placed in one file, any dependencies relate to the snippet they are in but remember to place those imports at the top of the file. As things progress splitting into multiple files is beneficial.

import { Signal } from 'raid'

const signal = new Signal()

The simplest setup for navigator is to hook in to the browser history which it will do by default which means that navigator just needs a signal and the navigation stack supplied to it, either add them as props directly or use something like reselect and adaptor from raid-addons to manage supplying props.

import { createSelector } from 'reselect'
import { adaptor } from 'raid-addons'
import { Navigator } from 'raid-navigator'

const connect = adaptor(signal)

const Navigation = connect(
  createSelector(
    state => state.navigation,
    (navigation) => ({
      navigation,
      signal
    })
  ),
  Navigator
)

Navigator aims to be easy to get set up and running, we just need one more step which is to implement the routes and render the app.

import { render } from 'react-dom'

signal.observe(state => {
  render(
    <Navigation>
      <div route='/'>
        <h1>Index</h1>
      </div>
      <div route='/settings'>
        <h1>Settings</h1>
      </div>
    </Navigation>
    document.querySelector('root')
  )
})

Navigator is now hooked up to state and will work to select routes based on pathname but we can still go a little further and make this more usable by adding a Link component which will update the navigation stack. Navigator exposes a few actions so to create the Link component we need to create something that pokes at the action and let navigator handle the rest.

import { push } from 'raid-navigator'

const Link = ({ children, route, state }) => (
  <a onClick={event => push(route, state)}>
    {children}
  </a>
)

Now update the render method to use the Link component.

render(
  <Navigation>
    <div route='/'>
      <h1>Index</h1>
      <Link route='/settings'>Go to settings</Link>
    </div>
    <div route='/settings'>
      <h1>Settings</h1>
      <Link route='/'>Go to index</Link>
    </div>
  </Navigation>,
  document.querySelector('root')
)

Memory history navigator

Creating a navigator based on memory history rather than browser history is also fairly straight forward but does require a little extra work.

To get started set up a raid signal as before but also instantiate a memory history implementation and use that to let navigator set things up.

import { Signal } from 'raid'
import { adaptor } from 'raid-addons'
import { Navigator } from 'raid-navigator'
import createHistory from 'history/createMemoryHistory'

const signal = new Signal()
const connect = adaptor(signal)
const history = createHistory()

We’ll supply the navigator with props using reselect and adaptor again, this time passing in the history instance we want navigator to use. If you’re planning on running this in the browser then navigator will still try to use sessionStorage by default which can (depending on your use-case) result in inconsistent behaviour. As it is often unnecessary or undesirable to store the state for long when using in-memory history we’re just going to disable the storage.

import { createSelector } from 'reselect'

const Navigation = connect(
  createSelector(
    state => state.navigation,
    (navigation) => ({
      history,
      navigation,
      signal,
      storage: null
    })
  ),
  Navigator
)

To make the navigator more usable we could do with a Link function again and navigator exposes a helper to create the actions hooked up to the new history instance.

import { createActions } from 'raid-navigator'

const { push } = createActions(history)

const Link = ({ children, route, state }) => (
  <button onClick={event => push(route, state)}>
    {children}
  </button>
)

And thats it, just a few quick changes to use memory history instead of browser history.

Route parameters

The match algorithm will also collect up route parameters and pass those to children as props under the params key. Route parameters are delimited by starting with /:.

const View = ({ params: { title } }) => <h1>{title}</h1>

render(
  <Navigation>
    <View route='/foo/:title' />
    <View route='/bar/:title' />
  </Navigation>,
  document.querySelector('root')
)

Match on all routes or subroutes

The match algorithm also honours * routes as a wildcard to match against all routes or subroutes.

const View = ({ params: { title } }) => <h1>{title}</h1>

render(
  <Navigation>
    <View route='/foo/*' />
    <View route='/bar/*' />
  </Navigation>
  document.querySelector('root')
)

Route Matching Component

Navigator is a connected component that attaches to the signal, however, sometimes you might want a supplementary component on your view that can react to url changes but is not connected to a history store.

RouteMatcher just implements the route matching algorithm to choose a child without the connectivity that Navigator supplies.

import { render } from 'react-dom'

signal.observe(state => {
  render(
    <RouteMatcher navigation={state.navigation}>
      <div route='/home/*'>Matched on home</div>
      <div route='/settings/*'>Matched on settings</div>
    </RouteMatcher>,
    document.querySelector('root')
  )
})

API—Navigator

  signal: RaidSignal<Required>,
  history: HistoryImpl,
  root: String,
  navigation: Object<Required>,
  Component: Function || Element || Node,
  ComponentProps: Object,
  mapChildren: Function

Most properties are optional, only a navigation object and the Raid Signal to operate against are required.

navigation

The navigation object is the navigation state that Navigator persists with the Raid Signal, it does this automatically for you but if you already have a history implementation under a separate key in your Raid Signal then you can supply the state here—this would be extremely rare though and altering the key is discouraged.

signal

Passing in a Raid Signal is required to hook up the Navigator to the various events that can trigger a navigation event and includes pre-filling the navigation state when the Navigator is instantiated.

history

Defaults to history.createBrowserHistory.

Browser history is the primary target for Navigator but any implementation (such as history.createMemoryHistory) that matches the specification set out by history should work fine.

Note that the default actions exposed by Navigator expect to hook in to browser history, if you supply a different history implementation then you’ll also want to create actions based on that history to hook everything up. See the navigatorMemory example for clarity.

root

This simply tells Navigator where it can find the navigation state. It’s not advised to change this, but, if absolutely necessary then you can. It’s just a string that is expected to match the key used in the signal to hold the navigation state.

Component

Want to wrap your returned route/s in a component? Supply it using Component. Useful for implementing animation on route changes.

ComponentProps

This object is spread as props to the Component specified, if you do not supply a Component then this is ignored.

mapChildren

This function is used to transform all children supplied to the Navigator component and will occur before attempting to match on a child or children. This can be very useful for wrapping children in a component to help manage animating route changes.

Running tests

$ npm
$ npm test

Contributing

Pull requests are always welcome, the project uses the standard code style. Please run npm test to ensure all tests are passing and add tests for any new features or updates.

For bugs and feature requests, please create an issue.

See the root readme for more information about how the repository is structured.

License

MIT