All Projects → UnicornHeartClub → react-keybind

UnicornHeartClub / react-keybind

Licence: MIT license
A lightweight library to manage global keyboard shortcuts for your React application

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to react-keybind

Evscript
A tiny sandboxed Dyon scripting environment for evdev input devices that lets you do e.g. xcape in Wayland
Stars: ✭ 91 (+160%)
Mutual labels:  keyboard-shortcuts
Keyboardjs
A JavaScript library for binding keyboard combos without the pain of key codes and key combo conflicts.
Stars: ✭ 1,881 (+5274.29%)
Mutual labels:  keyboard-shortcuts
Keymapper
📱 An Android app that maps any keys to actions.
Stars: ✭ 207 (+491.43%)
Mutual labels:  keyboard-shortcuts
Gibbon Tabs
The Chrome tab manager you always wanted.
Stars: ✭ 107 (+205.71%)
Mutual labels:  keyboard-shortcuts
Aquatouch
Dynamic Custom Macros for your MacBook TouchBar! (Supports 40+ Apps and Websites)
Stars: ✭ 125 (+257.14%)
Mutual labels:  keyboard-shortcuts
Chromium Vim
Vim bindings for Google Chrome.
Stars: ✭ 2,150 (+6042.86%)
Mutual labels:  keyboard-shortcuts
Xcactionbar
"Alfred for Xcode" plugin
Stars: ✭ 1,217 (+3377.14%)
Mutual labels:  keyboard-shortcuts
keys
⌨️ Keyboard Shortcuts for 'shiny'
Stars: ✭ 37 (+5.71%)
Mutual labels:  keyboard-shortcuts
Mousetrap
Simple library for handling keyboard shortcuts in Javascript
Stars: ✭ 10,937 (+31148.57%)
Mutual labels:  keyboard-shortcuts
Hawck
Key-rebinding daemon for Linux (Wayland/X11/Console)
Stars: ✭ 198 (+465.71%)
Mutual labels:  keyboard-shortcuts
Clavier Plus
Clavier+ keyboard shortcuts manager for Windows
Stars: ✭ 109 (+211.43%)
Mutual labels:  keyboard-shortcuts
Ng Keyboard Shortcuts
Dead Simple Keyboard Shortcuts Management for Angular
Stars: ✭ 121 (+245.71%)
Mutual labels:  keyboard-shortcuts
Ghostskb
Smart input method switcher like a ghost
Stars: ✭ 186 (+431.43%)
Mutual labels:  keyboard-shortcuts
Cropper
Point and shoot screen captures
Stars: ✭ 100 (+185.71%)
Mutual labels:  keyboard-shortcuts
Powerkey
Remap your Macbook's power key to Forward Delete
Stars: ✭ 212 (+505.71%)
Mutual labels:  keyboard-shortcuts
Quickcut
QuickCut is a cross-platform keyboard manager that both facilitates key mapping and allows the configuration of global hotkeys triggering user defined actions.
Stars: ✭ 84 (+140%)
Mutual labels:  keyboard-shortcuts
Macos Fn Toggle
A macOS app to quickly toggle the behavior of the fn key.
Stars: ✭ 178 (+408.57%)
Mutual labels:  keyboard-shortcuts
MyAHKScript
An AutoHotkey script that I use on the daily basis for my PC. Comes with an installer that takes care of everything for you.
Stars: ✭ 22 (-37.14%)
Mutual labels:  keyboard-shortcuts
Todoist Shortcuts
Comprehensive keyboard shortcuts for Todoist, via browser extension
Stars: ✭ 225 (+542.86%)
Mutual labels:  keyboard-shortcuts
Init.nvim
An Opinionated Neovim Config for the Minimalists
Stars: ✭ 194 (+454.29%)
Mutual labels:  keyboard-shortcuts

react-keybind ⌨️

npm david-dm Build Status

A lightweight library to manage global keyboard shortcuts for your React application. Just how lightweight is it?

minified size minzipped size

Who should use this library?

  • Your application contains many components that require keyboard shortcuts
  • Your application frequently changes keyboard shortcuts depending on the screen
  • Your application needs a list of all active shortcuts on the screen
  • Your application needs a simple way to manage keyboard shortcuts

Why another keyboard shortcut library?

We wrote react-keybind with a few main goals:

  • No External Dependencies - We wanted full control over the experience and size of the library
  • No RFC/Experimental Features - We wanted to build on top of a stable API
  • TypeScript Support - We wanted to support TypeScript

Features

  • Register shortcuts for single keypresses
  • Register shortcuts for combination keypresses (e.g. ctrl+c, ctrl+alt+a)
  • Register shortcuts for keypresses held after a duration
  • Register shortcuts for sequenced keypresses (e.g. up, up, down, down, enter)
  • Creates one listener for all keyboard shortcuts - fast and lightweight!

Roadmap

  • Focus - Support executing shortcuts when a particular element is focused

Installation

$ yarn add react-keybind

Requirements

This library uses React Context which requires React 16.3+.

TypeScript

This library utilizes TypeScript and exposes a full set of TypeScript definitions.

Usage

This library exposes a default withShortcut Higher-Order Component which is used to wrap any component that wants to utilize keyboard shortcuts.

Your main application should be wrapped in the exposed <ShortcutProvider />.

Example

import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import { withShortcut, ShortcutProvider, ShortcutConsumer } from 'react-keybind'

/**
 * Sample component
 *
 * We define shortcuts when the component mounts. This is useful because we can globally keep track
 * of what keyboard shortcuts _currently_ exist for our application.
 *
 * This sample component utilizes CTRL+N and CTRL+S to "create" and "save" files. It shows the usage
 * of both a regular and async method being used as a shortcut for the app.
 */
class MyComponent extends PureComponent {
  state = {
    isSaved: false,
    totalFiles: 0,
  }

  componentDidMount () {
    const { shortcut } = this.props

    shortcut.registerShortcut(this.save, ['ctrl+s', 'cmd+s'], 'Save', 'Save a file')
    shortcut.registerShortcut(this.create, ['ctrl+n', 'cmd+n'], 'New', 'Create a new file')
  }

  componentWillUnmount () {
    const { shortcut } = this.props
    
    shortcut.unregisterShortcut(['ctrl+n', 'cmd+n'])
    shortcut.unregisterShortcut(['ctrl+s', 'cmd+s'])
  }

  create = (e) => {
    e.preventDefault()
    console.log('Creating file ...')

    const { totalFiles } = this.state
    this.setState({
      isSaved: false,
      totalFiles: totalFiles + 1,
    })
  }

  save = async (e) => {
    e.preventDefault()
    console.log('Saving file ...')

    await new Promise(resolve => setTimeout(resolve, 1000))
    this.setState({ isSaved: true })
  }

  render() {
    const { isSaved, totalFiles } = this.state

    return (
      <div>
        <div>Save the file with <strong>Ctrl + S</strong></div>
        <div>File status: {isSaved ? 'Saved' : 'Not Saved'}</div>
        <div>Total Files: {totalFiles}</div>
      </div>
    )
  }
}

// Wrap all components that need shortcut capabilities with the "withShortcut" HOC
const MyShortcutComponent = withShortcut(MyComponent)

/**
 * Main Application
 *
 * Our main application gets wrapped with <ShortcutProvider /> to provide shortcut functionality
 * to the entire application. We can then use the <ShortcutConsumer /> in any child component to
 * access all of the active keybindings our application has.
 */
const MyApp = () => (
  <ShortcutProvider>
    <MyShortcutComponent />

    <ShortcutConsumer>
      {({ keys: allKeys }) => (
        <div>
          <h1>Available Keys</h1>
          <ul>
            {allKeys.map(binding => (
              <li key={binding.id}>{binding.title} - {binding.description}</li>
            ))}
          </ul>
        </div>
      )}
    </ShortcutConsumer>
  </ShortcutProvider>
)

// That's it, render your application however you normally do
ReactDOM.render(MyApp, '#app')

The same component above, using React Hooks:

import React, { useCallback, useEffect, useState } from 'react'

const MyComponent = (props) => {
  const [state, setState] = useState({
    isSaved: false,
    totalFiles: 0,
  })

  const create = useCallback((e) => {
    e.preventDefault()
    console.log('Creating file ...')

    setState(({totalFiles}) => ({
      isSaved: false,
      totalFiles: totalFiles + 1,
    }))
  }, [state])
 
  const save = useCallback(async (e) => {
    e.preventDefault()
    console.log('Saving file ...')
 
    await new Promise(resolve => setTimeout(resolve, 1000))
    setState(({totalFiles}) => ({
      isSaved: true,
      totalFiles: totalFiles,
    }))
  }, [state])

  useEffect(() => {
    const { shortcut } = props
 
    shortcut.registerShortcut(save, ['ctrl+s', 'cmd+s'], 'Save', 'Save a file')
    shortcut.registerShortcut(create, ['ctrl+n', 'cmd+n'], 'New', 'Create a new file')
    return () => {
      const { shortcut } = props
      shortcut.unregisterShortcut(['ctrl+n', 'cmd+n'])
      shortcut.unregisterShortcut(['ctrl+s', 'cmd+s'])
    }
  }, [])

  const { isSaved, totalFiles } = state

  return (
    <div>
      <div>Save the file with <strong>Ctrl + S</strong></div>
      <div>File status: {isSaved ? 'Saved' : 'Not Saved'}</div>
      <div>Total Files: {totalFiles}</div>
    </div>
  )
}

API

react-keybind exposes a small set of Components to use in your application.

<ShortcutProvider />

Initializes the main provider for shortcuts. This component should be placed at the root of your application where you want to start listening on keyboard shortcuts.

Props

Prop Type Default Description
ignoreKeys string[] [] Array of keys to ignore (e.g. ['shift', 'ctrl'])
ignoreTagNames string[] ['input'] Array of tagNames to ignore (e.g. ['input', 'article'])
preventDefault boolean true Call preventDefault() automatically when a shortcut is executed

withShortcut(React.ReactNode)

Higher-Order Component to wrap your components with. Provides the following methods and state:

shortcut: {
  registerShortcut?: (
    method: (e?: React.KeyboardEvent<any>) => any,
    keys: string[],
    title: string,
    description: string,
    holdDuration?: number,
  ) => void
  registerSequenceShortcut?: (
    method: () => any,
    keys: string[],
    title: string,
    description: string,
  ) => void
  shortcuts: Shortcut[]
  triggerShortcut?: (key: string) => any
  unregisterShortcut?: (keys: string[]) => void
}

<ShortcutConsumer />

An optional consumer that providers the same properties as the withShortcut HOC. Can be used as a direct way to access current shortcuts or access methods for register/unregister new shortcuts.

Use Cases

This library was built specifically for Astral TableTop, an online platform to play tabletop roleplaying games with people from all around the world.

The Astral platform contains many different screens than handle a wide variety of purposes such as a full-featured map editor and a unique online game screen for both Game Masters and players. Each screen in Astral might contain several dozens of keyboard shortcuts.

Instead of managing each screen individually and keeping track of which shortcuts are used where, we simplify the process by letting components decide which shortcuts they want to define and tracking the list of active shortcuts globally. This is especially useful for rendering a quick "Shortcut Menu" for our users no matter where the user might be in the application.

We open-sourced this library in hopes that other projects might find it useful 💙

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].