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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@karrotframe/navigator-legacy

v0.23.1

Published

UX Enhancer

Readme

Light-weight stack navigator for React

  • 🗂 History support
  • 💅 Beautiful page transition animation designed for each platform (Android/iOS)
  • ⚙️ Navigation bar designed for each platform
  • 🪄 Automatically attach close or back button for each circumstance

Core logic of Navigator depends on react-router-dom



Setup

$ yarn add @karrotframe/navigator

Should import the CSS of your app

import '@karrotframe/navigator/index.css'

import { ... } from '@karrotframe/navigator'

Components

Navigator

The Navigator component includes elements that are necessary to express the screen. Please include it at the top of the component tree

All the props is typed and commented in TypeScript

import { Navigator } from '@karrotframe/navigator'

const App: React.FC = () => {
  return (
    <Navigator
      theme="Cupertino"
      onClose={() => {
        console.log('Close button is pressed')
      }}
    >
      {/*...*/}
    </Navigator>
  )
}

If you use the useCustomRouter option, you can provide a router other than HashRouter.

import { Navigator } from '@karrotframe/navigator'
import { HashRouter } from 'react-router-dom'

const App = () => {
  return (
    <HashRouter>
      <Navigator useCustomRouter>...</Navigator>
    </HashRouter>
  )
}

Screen

The Screen component is used to declare a screen. Declare it inside Navigator.

All the props is typed and commented in TypeScript

import { Navigator, Screen } from '@karrotframe/navigator'

const App: React.FC = () => {
  return (
    <Navigator
      theme="Cupertino"
      onClose={() => {
        console.log('Close button is pressed')
      }}
    >
      <Screen path="/" component={MyComponent} />
      {/* or */}
      <Screen path="/">
        <MyComponent />
      </Screen>
    </Navigator>
  )
}

Be sure to use component or children (if both props are declared at the same time, component takes precedence)

ScreenHelmet

By default, Screen does not include a top navigation bar. To add or modify the built-in top navigation bar, use the ScreenHelmet component.

All the props is typed and commented in TypeScript

import { ScreenHelmet } from '@karrotframe/navigator'

const MyComponent: React.FC = () => {
  return (
    <div>
      <ScreenHelmet
        title="My App"
        appendLeft={<div>Append to Left</div>}
        appendRight={<div>Append to Right</div>}
        customBackButton={<div>Back</div>}
        customCloseButton={<div>Close</div>}
      />
    </div>
  )
}

Hooks

useNavigator

Trigger a screen transition.

All arguments are typed and commented in TypeScript

import { useNavigator } from '@karrotframe/navigator'

const Posts: React.FC = () => {
  const { push, pop, replace } = useNavigator()

  const goPost = (postId: string) => () => {
    // Go to a specific path
    push(`/posts/${postId}`)

    // Opens a specific path in a new window that cannot be swipe back (Cupertino theme only)
    push(`/posts/${postId}`, {
      present: true,
    })
  }

  const goBack = () => {
    // Go one step back
    pop()

    // Multiple levels can be popped through the depth argument
    pop(1)
  }

  useEffect(() => {
    if (!user) {
      // Move to a specific path (replace)
      // It moves without animation, so it is suitable for redirect behavior.
      replace('/login')
    }
  })

  return (
    <div>
      {posts.map((post) => {
        return (
          <div>
            {/* ... */}
            <button onClick={goPost(post.id)}>View article details</button>
          </div>
        )
      })}
      {/* ... */}
      <button onClick={goBack}>Back</button>
    </div>
  )
}

useCurrentScreen

Get current screen's information

All arguments are typed and commented in TypeScript

import { useCurrentScreen } from '@karrotframe/navigator'

const Posts: React.FC = () => {
  const { isTop, isRoot } = useCurrentScreen()

  return (
    <div>
      {isTop && <span>This screen is in top</span>}
      {isRoot && <span>This screen is in root</span>}
    </div>
  )
}

useParams

To prevent unintentional screen changes due to changes in the path between screen transitions, you can use a path parameter through useParams.

All arguments are typed and commented in TypeScript

import { useParams } from '@karrotframe/navigator'

const Post: React.FC = () => {
  /**
   * Value entered as path parameter (not changed in screen transitions)
   */
  const params = useParams()

  return /* ... */
}

useQueryParams

To prevent unintentional screen changes due to changes in the path between screen transitions, you can use a querystring through useQueryParams.

All arguments are typed and commented in TypeScript

import { useQueryParams } from '@karrotframe/navigator'

const Post: React.FC = () => {
  /**
   * Value entered as querystring (not changed in screen transitions)
   */
  const querystring = useQueryParams()

  return /* ... */
}

Advance

Nested Routes

Use Route in react-router-dom

// <Screen path='/example' component={ExampleScreen} />

import { Route, useHistory } from 'react-router-dom'

const ExampleScreen = () => {
  const history = useHistory()

  const moveToInside2 = () => {
    history.push('/example/inside2')
  }
  const goBack = () => {
    history.goBack()
  }
  const goBackFurther = () => {
    // You can go back by integrating the current internal routing
    // with the previous Karrotframe screen transitions.
    history.go(-4)
  }

  return (
    <div>
      <Route path="/example/inside1">...</Route>
      <Route path="/example/inside2">...</Route>
    </div>
  )
}

If the _si query string is not included in the path, Karrotframe recognizes it as an internal routing and does not perform any separate animation processing.

await push()

You can transfer data between screens through pop().send() and await push() of useNavigator.

When the depth argument in the pop() function is set to 2 or more, it is possible to send over multiple screens.

import { useNavigator } from '@karrotframe/navigator'

const Posts: React.FC = () => {
  const { push } = useNavigator()

  const writePost = () => {
    // Wait for the data to be sent from the next screen
    const data = await push('/posts/write')
    console.log(data)
    // {
    //   hello: 'world',
    // }
  }
  return (
    <div>
      <button onClick={writePost}>Write post</button>
    </div>
  )
}

const PostWriteForm: React.FC = () => {
  const { pop } = useNavigator()

  const onSubmit = () => {
    // Transfer data to previous screen
    pop().send({
      hello: 'world',
    })

    // It is also possible to transfer data by skipping several steps as shown below.
    pop(3).send({
      hello: 'world',
    })
  }

  return /* ... */
}

react-router-dom APIs

You can use useLocation, useRouteMatch and useHistory that exist in react-router-dom.

import { useLocation, useHistory, useRouteMatch } from 'react-router-dom'

const Post: React.FC = () => {
  /**
   * Current location information
   */
  const location = useLocation()

  /**
   * History API
   */
  const history = useHistory()

  /**
   * Compares the current location with a specific path regex and returns the parsed value.
   */
  const match = useRouteMatch({
    path: '/:post_id',
  })

  return /* ... */
}