1.4.32 โ€ข Published 9 months ago

kmenu v1.4.32

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

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 hi.harsh@pm.me.

๐Ÿš€ Quickstart

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

Install the npm package:

yarn add kmenu

Using the Provider

After you install, you must wrap your application around the MenuProvider component. Wanna learn how you can customize your menu configuration? Check out the MenuConfig section.

Inside the MenuProvider, you can pass in the theme configuration which all the menus will use. All props are optional, and you can also pass in props if your commands or sections have extra margin between them. Here's a look:

ParameterDescriptionTypeOptional
configThe config file passed onto the paletteConfigโœ…
dimensionsThe values of the height of the palettes (px)Dimensionโœ…

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

ParameterDescriptionTypeDefaultOptional
commandHeightThe height of each command in the palette (px)number54โœ…
sectionHeightThe height of each category/section in the palette (px)number31โœ…

Below is an example:

import { MenuProvider, MenuConfig } from 'kmenu'

const App = () => {
  const config: MenuConfig = {
    /* ... */
  }

  return <MenuProvider config={config}>{/* ... */}</MenuProvider>
}

Adding commands

After you've installed the package, you can now begin adding commands onto the command menu.

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

ParameterDescriptionTypeOptional
categoryThe name of the category the command will be displayed instringโŒ
commandsAn array of commands passed onto the categoryCommandโŒ

Awesome. Now here's a look at how you can create commands:

ParameterDescriptionTypeOptional
iconThe icon displayed next to the commandReactElementโœ…
textThe text displayed on the commandStringโŒ
performThe action to performvoidโœ…
hrefThe link to openvoidโœ…
newTabWhether or not the link should open in a new tabbooleanโœ…
keywordsSearch keywords for the commandstringโœ…
shorcutsThe keyboard shortcuts to activate this commandShortcutโœ…
closeOnCompleteWhether the menu should close when the command is run (default: false)booleanโœ…

As you might notice, the commands give you the ability to define custom shortcuts.

Each shortcut can have two target keys and a modifier that would be used in conjunction with a single target key. Note that if you're using a modifier, you can only use a SINGLE target key. Here's a look at how you can create shortcuts:

ParameterDescriptionTypeOptional
modifierThe modifier key used in conjunction with the target keyenum (shift/alt/ctrl/meta)โœ…
keysThe target keys for this commandTuple string, string?โŒ

After you've created all your commands, you must pass them into the useCommands hook, which returns a getter and a setter for the commands. For a reference, check out the section on the useCommands hook.

NOTE: THE SHORTCUTS PROPERTY IS PURELY COSMETIC AND HAS NO FUNCTIONALITY.

Now that you have an underlying idea of how commands work, here's an example of how to create the commands (using TypeScript):

import {
  Search,
  Copy,
  Globe,
  GitHub,
  AlertCircle,
  GitPullRequest,
  Zap,
  Edit2,
  Plus,
  Settings,
  Code,
  Command as Cmd,
  Terminal
} from 'react-feather'

const main: Command[] = [
  {
    category: 'Socials',
    commands: [
      {
        icon: <FiGlobe />,
        text: 'Website',
        href: 'https://hxrsh.in',
        newTab: true,
        keywords: 'home'
      },

      {
        icon: <FiTwitter />,
        text: 'Twitter',
        href: 'https://twitter.com/harshhhdev',
        newTab: true,
        shortcuts: { modifier: 'alt', keys: ['t'] }
      },
      {
        icon: <FiGithub />,
        text: 'GitHub',
        href: 'https://github.com/harshhhdev',
        newTab: true,
        shortcuts: { keys: ['g', 'h'] }
      },
      {
        text: 'Dribbble',
        href: 'https://dribbble.com/harshhhdev',
        newTab: true
      },
      {
        icon: <FiLinkedin />,
        text: 'Linkedin',
        href: 'https://linkedin.com/in/harshhhdev',
        newTab: true
      }
    ]
  }
]

const Component = () => {
  const [commands, setCommands] = useCommands(main)

  /* ... */
}

useKmenu Hook

useKmenu is a utility hook that gives you some useful functions and 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:

ParameterDescriptionType
inputThe current text in the search bar of the menu that is currently openstring
setInputThe setter function to change the inputDispatch<SetStateAction>
isOpenThe index of the menu is currently open() => boolean
openThe index of the menu is currently opennumber
setOpenThe setter function to change the open state(index: number, preventAnimate?: boolean) => void
toggleThe function for toggling the main menu open/close() => void

With that, here's also a code example of how you could use this hook.

NOTE: YOU MUST WRAP YOUR COMPONENT INSIDE THE MenuProvider TO USE THIS HOOK.

import { useKmenu } from 'kmenu'

const Component = () => {
  const { input, open, toggle } = useKmenu()

  return (
    <div>
      <p>The current text on the search bar is: {input}</p>
      <p>The index of the menu which is currently open is: {open}</p>
      <button onClick={toggle}>Toggle Menu</button>
    </div>
  )
}

useCommands Hook

With kmenu v1, you can now dynamically compute and define commands.

When commands are inputted into the useCommands hook, they're returned into an object of command-menu parsable commands, and they require an initial value of the commands you'd like to pass in.

NOTE: YOU CANNOT USE SetCommands DIRECTLY INSIDE OF A useEffect HOOK AT RENDER

Here's an example of the hook live in action:

import { CommandMenu, Command, useCommands } from 'kmenu'

const Component = () => {
  const main: Command[] = [
    /* ... */
  ]

  const [commands, setCommands] = useCommands(main)

  return
  ;<CommandMenu commands={commands} crumbs={['Home']} index={1} main />
}

Customizing the menu

You can easily customize the colors on your command menu as well. Here's a list of properties that are customisable:

NOTE: ALL PROPERTIES ARE OPTIONAL

ParameterDescriptionTypeDefault
backdropColorThe color of the backdrop (include opacity)string#FFFFFF90
backdropBlurThe backround blur of the backdrop (px)number2px
backgroundColorThe background color of the menustring#FFFFFF
breadcrumbColorThe background color of the breadcrumbsstring#FFFFFF
breadcrumbRadiusThe border radius of the breadcrumbsstring5px
borderWidthWidth of the border surrounding the menunumber1px
borderColorThe color of the border surrounding the menustring#3F3F3F
borderRadiusThe radius of the menu (px)number10px
boxShadowThe shadow of the menustring0px 0px 60px 10px #00000020
inputBorderThe color of the border below the search barstring#E9ECEF
inputColorThe color of the text in the search barstring#000000
headingColorThe color of the command category headingsstring#777777
commandInactiveThe color of the icon and text when the command is inactivestring#828282
commandActiveThe color of the icon and text when the command is activestring#343434
barBackgroundThe background color of the active bar (include opacity)string#FFFFFF20
shortcutBackgroundThe background color of the keyboard shortcutstring#82828220
animationDurationThe duration of the dialog opening animationnumber0.1

Setting up the menu

Be sure to wrap our menu around a CommandWrapper component. Here are all the properties you can pass into it:

ParameterDescriptionTypeOptional
valueThe default value on this particular menustringโœ…

Here are all the options available on the menu:

ParameterDescriptionTypeOptional
commandsThe commands for this menu to displayCommand[]โŒ
subCommandsCommands availiable only by searchCommand[]โœ…
indexThe index of this menunumberโŒ
crumbsThe current path of the command menustring[]โŒ
preventSearchDisable filtering results for the menustringโœ…
loadingPlaceholderElement to be displayed while commands loadReactElementโœ…
loadingStateWhether or not the data is currently loadingbooleanโœ…
placeholderThe placeholder text on this particular menustringโœ…

Once you have added commands to the menu and configured it to you preferences, you can add it into your application. Add in the CSS file for styling. Optionally, if you'd like to FULLY customize the styles on the menu to your likings then you can copy the index.css file from the repository and import that instead. You'll also need to create a useState hook for handling the state.

NOTE: YOU MUST WRAP YOUR MENU INSIDE OF THE MenuProvider FOR IT TO WORK

import { useState } from 'react'
import { CommandMenu, Command, MenuConfig } from 'kmenu'
import 'kmenu/dist/index.css'

const Component = () => {
  const commands: Command[] = [
    /* ... */
  ]
  const config: MenuConfig = {
    /* ... */
  }
  const categories: string[] = [
    /* ... */
  ]

  return (
    <MenuProvider config={config}>
      /* ... */
      <CommandWrapper>
        <CommandMenu commands={commands} index={1} crumbs={['Home']} main />
      </CommandWrapper>
      /* ... */
    </MenuProvider>
  )
}
/* ... */
export default Component

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

Nested Menus

This library also provides support for nested menus and commands. Here's an example to help you out:

import { useState } from 'react'
import { Menu, Command, useKmenu, useCommands } from 'kmenu'
import 'kmenu/dist/index.css'

const Component = () => {
  const main: Command[] = [
    {
      category: 'Navigation',
      commands: [
        {
          icon: <FiGlobe />,
          text: 'Website',
          href: 'https://hxrsh.in',
          newTab: true,
        },
        {
          icon: <FiArrowRight />,
          text: 'Nested Example...',
          perform: () => setOpen(2),
        },
      ]
    }
  ]

  const nested: Command[] = [
    {
      category: 'Navigation',
      commands: [
        {
          icon: <FiGlobe />,
          text: 'Demo',
          href: 'https://kmenu.hxrsh.in',
          newTab: true,
        },
        {
          icon: <FiGlobe />,
          text: 'GitHub',
          href: 'https://github.com/harshhhdev/kmenu',
          newTab: true,
        },
      ]
    }
  ]

  const { setOpen } = useKmenu()
  const [mainCommands, setMainCommands] = useCommands(main)
  const [nestedCommands, setNestedCommands] = useCommands(nested)

  return (
    {/* ... */}
    <CommandMenu
      commands={mainCommands}
      crumbs={['Home']}
      index={1}
      main
    />
    <CommandMenu
      commands={nestedCommands}
      crumbs={['Home', 'Example']}
      index={2}
    />
    {/* ... */}
  )
}
/* ... */
export default Component

If this isn't enough, there's also an example directory which you can clone and experiment around with to build nested routes.

useShortcut hook

This library also ships with a custom React hook called useShortcut which you can use to define your own shortcuts within your application.

ParameterDescriptionTypeOptional
targetKeyThe key that the shortcut is listening forstring (must be valid key)โŒ
modifierThe modifier key which can will activate the shortcutenum (shift/alt/ctrl/meta)โœ…

Here's an example:

import { useShortcut } from 'kmenu'

const Shortcut = () => {
  const shiftS = useShortcut({ targetKey: 's', modifier: 'shift' })

  /* ... */
}

export default Shortcut

The example below will run when someone uses the keyboard shortcut shift+s.

Development

Run the project locally

git clone https://github.com/harshhhdev/kmenu.git

Setting up the project

cd kmenu
yarn

# Setup example directory
cd example
yarn

Next, start the development server:

yarn start

This should compile an instance of your project to the dist folder. It should re-build everytime you save a new change.

Using the package

You can test the built package locally by running the example repository:

cd example

# Start development server
yarn start

Awesome. Your React development server should now be running on port 3000.

Inspirations

1.4.3

9 months ago

1.4.2

10 months ago

1.4.11-beta

11 months ago

1.4.1-beta

11 months ago

1.3.1-beta

11 months ago

1.4.31

9 months ago

1.4.32

9 months ago

1.4.0-beta

11 months ago

1.3.0-beta

11 months ago

1.2.2-dev

1 year ago

1.2.2-nightly

1 year ago

1.2.0-dev

1 year ago

1.2.0-nightly

1 year ago

1.2.1-dev

1 year ago

1.1.0-beta

2 years ago

1.0.6-beta

2 years ago

1.0.8-beta

2 years ago

1.0.7-beta

2 years ago

1.0.9-beta

2 years ago

1.0.5-beta

2 years ago

1.0.4-beta

2 years ago

1.0.3-beta

2 years ago

1.0.2-beta

2 years ago

1.0.1-beta

2 years ago

1.0.0-beta-git

2 years ago

1.0.0-beta-dev

2 years ago

1.0.0-beta

2 years ago

1.0.0-git

2 years ago

1.0.0-dev

2 years ago

1.0.0-dev-git

2 years ago

0.0.25-dev

2 years ago

0.0.25-beta

2 years ago

0.0.25

2 years ago

0.0.24

2 years ago

0.0.23-beta

2 years ago

0.0.22

2 years ago

0.0.21

2 years ago

0.0.2-dev

2 years ago

0.0.2

2 years ago