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

kmenu

v2.0.0

Published

🌈 Animated and accessible cmdk interface

Downloads

2,982

Readme

image

Consulting

If you're a startup or founder using this for your application and need some help setting it up, or perhaps even need a separate cmdk interface tailored to your application, you can reach out to at [email protected].

Quickstart

View the official documentation for more thorough examples and documentation.

Having trouble? Unsure of something? Feel free to ask away in the discussions.

Install the npm package:

npm add kmenu
yarn add kmenu
pnpm add kmenu

Using the Provider

After you install, you must wrap your application around the MenuProvider component. If your application has some values (padding/margin/etc) which override the styles of the menu, you need to explicitly define the height of each command component and each section in your code. Here's a look:

| Parameter | Description | Type | Optional | | ---------- | ---------------------------------------------------- | ---------- | -------- | | dimensions | Height values of different elements in the menu (px) | Dimensions | βœ… |

Now, here's a look at the dimensions object:

| Parameter | Description | Type | Default | Optional | | ------------- | ----------------------------------------------------------------- | ------ | ------- | -------- | | commandHeight | The height of each command in the palette (px) | number | 54 | βœ… | | sectionHeight | The height of each category/section in the palette (px) | number | 31 | βœ… | | commands | The maximum number of commands displayed on menu without overflow | number | 5 | βœ… |

Here's how you'd use your menu provider:

import { MenuProvider, Dimensions } from 'kmenu'

export default ({ children }) => {
  const dimensions: Dimensions = {}

  return <MenuProvider dimensions={dimensions}>{children}</MenuProvider>
}

Commands

The commands are broken up into two arrays: an array that contains the different categories of the commands, and another array contains the commands itself. Here's how you can define categories:

| Parameter | Description | Type | Optional | | ----------- | ----------------------------------------------------------------------- | ------- | -------- | | category | The name of the category the command will be displayed in | string | ❌ | | commands | An array of commands passed onto the category | Command | ❌ | | subCommands | An array of commands passed onto the category only accessible by search | Command | βœ… |

Here's how you create commands:

| Parameter | Description | Type | Optional | | --------------- | --------------------------------------------------------- | ------------ | -------- | | icon | The icon displayed next to the command | ReactElement | βœ… | | text | The text displayed on the command | string | ❌ | | perform | The action to perform | void | βœ… | | href | The link to open | void | βœ… | | newTab | Whether or not the link should open in a new tab | boolean | βœ… | | keywords | Search keywords for the command | string | βœ… | | shorcuts | The keyboard shortcuts displayed on the command | Shortcut | βœ… | | closeOnComplete | Whether the menu should close after command executes | boolean | βœ… | | anchor | Allow for custom HTML to be passed as the anchor property | NavLink | βœ… | | checkbox | Add a checkbox to the command | Checkbox | βœ… |

We can create our commands array like this:

import type { Command } from 'kmenu'

const main: Command[] = [
  {
    category: 'Utility',
    commands: [
      {
        icon: <Dashboard />,
        text: 'Dashboard',
        href: '/dashboard',
        keywords: ['home', 'back'],
      },
      {
        icon: <Cloud />,
        text: 'Deployments',
        href: '/deployments',
      },
      {
        icon: <ArrowLeft />,
        text: 'Previous',
        perform: () => navigateToPreviousPage(),
        keywords: ['back']
      },
    ],
    subCommands: [
      {
        icon: <ExternalLink />,
        text: 'Home',
        href: '/',
        newTab: true,
      },
    ],
  },
]

Shortcuts

Each shortcut can have two target keys and a modifier:

| Parameter | Description | Type | Optional | | --------- | ----------------------------------------------------- | -------------------------------------- | -------- | | keys | The key(s) that the shortcut is listening for | [string, string?] (must be valid) | ❌ | | modifier | The modifier key which can will activate the shortcut | string (must be valid) or ReactElement | βœ… |

Command Wrapper

Be sure to wrap ALL your menus around a CommandWrapper component. This component contains things like the breadcrumbs and the search bar. You can pass in a default value for the input on the command wrapper:

| Parameter | Description | Type | Optional | | ------------ | ------------------------------ | ------ | -------- | | defaultValue | The default value on the input | string | βœ… |

Command Menu

Here are all the options available on the menu:

| Parameter | Description | Type | Optional | | ------------------ | -------------------------------------------- | ------------ | -------- | | commands | The commands for this menu to display | Command[] | ❌ | | index | The index of this menu | number | ❌ | | crumbs | The current path of the command menu | string[] | ❌ | | preventSearch | Disable filtering results for the menu | string | βœ… | | loadingPlaceholder | Element to be displayed while commands load | ReactElement | βœ… | | loadingState | Whether or not the data is currently loading | boolean | βœ… | | placeholder | The placeholder text on this particular menu | string | βœ… |

The index is the index of this menuβ€”if you only have a single menu, set this to one. This number is used for opening and closing multiple menus, whenever you want to open a sub menu simply use the setOpen command and input the index of the menu you'd like to open. For more information on this, see nested menus.

useCommands

After you define your components, you must input them into the useCommands hook. Learn more about it here.

export default () => {
  const main = [
    /* ... */
  ];
  const [mainCommands] = useCommands(main);

  return (
    <CommandWrapper>
      <CommandMenu commands={mainCommands} index={1} crumbs={['Home']} />
    </CommandWrapper>
  );
};

That's about all the configuration you'll need to do in order to get a basic command menu to work.

The possibilities are with these menus infinite: you can add custom loading states, sub-commands, and so much more. For a full list, check out the examples.

useKmenu Hook

useKmenu is a utility hook that adds utility and gives you information about the current status of the menu. You can use these for a multitude of different things such as nested routes on the command menu or for toggling the menu through a button on your UI.

Here's a list of all the information it provides:

| Parameter | Description | Type | | --------- | --------------------------------------------------------------------- | ------------------------------------------------- | | input | The current text in the search bar of the menu that is currently open | string | | setInput | The setter function to change the input | Dispatch<SetStateAction<string>> | | isOpen | Whether or not the menu is currently open | boolean | | open | The index of the menu is currently open | number | | setOpen | The setter function to change the open state | (index: number, preventAnimate?: boolean) => void | | toggle | The function for toggling the main menu open/close | void |

Here's an example of how you can toggle the menu open with the click of a button:

import { useKmenu } from 'kmenu'

export default () => {
  const { toggle } = useKmenu()
  return <button onClick={toggle}>Toggle Menu</button>
}

REMINDER: YOUR APPLICATION OR PARENT COMPONENT MUST BE WRAPPED IN THE MENUPROVIDER

Examples

In an attempt to showcase everything this menu can do, examples/src/kmenu includes an ever-growing list some things you can do with kmenu:

This list is ever-growing. If there's something you ever want to add, any and all pull requests are always welcomed.