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

react-keyboard-control

v1.2.5

Published

A lightweight library for manipulating state with (a series of) keystrokes

Downloads

17

Readme

react-keyboard-control

This library is meant to provide a simple React hook useKeyboardControl() which can be used to manage a list of keyboard hooks (keyboard inputs and associated callbacks). Features supported by react-keyboard-control:

  • Assign a callback function for a given keyboard event
  • Use any available field in the KeyboardEvent type (see MDN) to match the user input
  • Match a sequence of keyboard events
  • Disable keyboard hooks when used in a text field (input and textarea)
  • Prevent matched keyboard events from being typed in a text field
  • Return the list of keyboard events being tracked in the current sequence
  • Filter certain keyboard hooks depending on state
  • Set the keyboard event type (keypress, keydown, keyup)

Install

npm install react-keyboard-control

Notes

  • {key: "t", shiftKey: true} will not match a capital T, because the actual key recorded will be "T", not "t". This applies for other keystrokes too, like option-o produces ø on my keyboard.
    • Note that keyboards can be a bit weird; users may have a Mac or Windows keyboard, and further use different layouts e.g. Dvorak. Since ø is the key recorded by the KeyboardEvent when I press option-o, that's how I would register the keyboard hook. But it might be possible that option-o produces a different key on a different keyboard.
  • KeyboardEvents that are only meta keys (e.g. command, option) are discarded immediately, since we usually only care about the non-meta key that eventually follows. In other words, you can match for ⌘; but not alone.
  • If a key event occurs which doesn't match any candidate keyboard hooks, the current key sequence will be discarded (think of hitting "escape")

Example

"use client";

import useKeyboardControl from "react-keyboard-control";
import { KeyboardHook, TypedKey } from "react-keyboard-control";
import { useCallback, useEffect, useState } from "react";

enum ColorThemes {
  LIGHT,
  DARK,
}

const LIGHT_COLOR_THEME = {
  color: "black",
  backgroundColor: "white",
};
const DARK_COLOR_THEME = {
  color: "white",
  backgroundColor: "black",
};

export default function Home() {
  const [colorTheme, setColorTheme] = useState(ColorThemes.LIGHT);
  const [lastUpdatedTime, setLastUpdatedTime] = useState(null as Date | null);
  const [timesPressedQ, setTimesPressedQ] = useState(0);

  // This is necessary to ensure time is fetched on client
  useEffect(() => setLastUpdatedTime(new Date()), []);

  const updateTime = () => {
    setLastUpdatedTime(new Date());
  };

  const incrementTimesPressedQ = useCallback(
    () => setTimesPressedQ(timesPressedQ + 1),
    [timesPressedQ]
  );

  const keyboardHooks: KeyboardHook[] = [
    // When command ;, l is pressed, set theme to light
    {
      keyboardEvent: [{ key: ";", metaKey: true }, { key: "l" }],
      callback: () => setColorTheme(ColorThemes.LIGHT),
    },
    // When command ;, d is pressed, set theme to dark
    {
      keyboardEvent: [{ key: ";", metaKey: true }, { key: "d" }],
      callback: () => setColorTheme(ColorThemes.DARK),
    },
    // When q is pressed, increment counter (even in text area)
    {
      keyboardEvent: { key: "q" },
      callback: incrementTimesPressedQ,
      allowOnTextInput: true,
    },
    // When @ is pressed, update time (prevented from being typed)
    {
      keyboardEvent: { key: "@" },
      callback: updateTime,
      allowOnTextInput: true,
      preventDefault: true,
    },
    // When l, o, n, g is typed in dark mode, send alert
    {
      keyboardEvent: [{ key: "l" }, { key: "o" }, { key: "n" }, { key: "g" }],
      callback: () => alert("that was a long key sequence"),
      allowWhen: colorTheme === ColorThemes.DARK,
    },
    // When control o (ø) is typed, send alert
    {
      keyboardEvent: [{ key: "ø" }, { key: "Enter" }],
      callback: () => alert("entered null"),
    },
  ];
  const currentSequence: TypedKey[] = useKeyboardControl(keyboardHooks);

  return (
    <>
      <div
        style={
          colorTheme === ColorThemes.LIGHT
            ? LIGHT_COLOR_THEME
            : DARK_COLOR_THEME
        }
      >
        <div>
          The current input sequence is:{" "}
          {currentSequence.map((k) => k.basicRepresentation).join(", ")}
        </div>
        <input defaultValue="You can type in here!" />
        <div>
          The last updated time was:{" "}
          {lastUpdatedTime && lastUpdatedTime.toTimeString()}
        </div>
        <div>You have pressed the letter q {timesPressedQ} times.</div>
      </div>
    </>
  );
}

Reference

useKeyboardControl(...)

  • keyboardHooks: A list of KeyboardHook objects, describing all the keyboard events to track and their associated callback functions.
  • eventType: Which of the keyboard events ("keydown", "keypress", "keyup") to track; defaults to "keydown".
  • allowEarlyCompletion: If set to true, then a KeyboardHook will be resolved as soon as it is the only remaining candidate for the current keystroke sequence; defaults to false (you can just shorten your key sequence).

KeyboardHook interface

A KeyboardHook is an object with the following:

  • keyboardEvent: This can be a single Partial<KeyboardEvent> or a list of them, if there are multiple keyboard events in the sequence. You can set any property of KeyboardEvent in order to match with the user's keyboard input (typically, just key will suffice).
  • callback: A function to execute when the keyboard hook is matched.
  • allowOnTextInput: If set to true, then this keyboard hook can still be triggered even if the target of the KeyboardEvent is an <input> or <textarea>. Defaults to false.
  • preventDefault: Whether to prevent the KeyboardEvent's default action, if it could be part of a key sequence. This can be used to prevent typing in a text input. Defaults to false.
  • allowWhen: If set, this can be used to filter out certain keyboard hooks based on state. For example, if ;w is a hook that saves your work, you may want to only allow it when the user is doing something save-able. The advantage of using this instead of inside the callback (e.g. () => isEditing() && save()) is that the hook won't think the user is in the middle of a sequence if they press ; in a non-saveable state.

TypedKey interface

This hook returns a list of TypedKeys as the list of keys being used in the current key sequence. A TypedKey contains two things: an event (the KeyboardEvent itself) and a basicRepresentation, which is a simple string representation of the keyboard event (e.g. "⇧T"). This output can be used to show the user what keystrokes are currently being considered by the keyboard control (similar to other editors like vi).