react-shortcut
Advanced tools
Comparing version 1.0.6 to 2.0.7
143
package.json
{ | ||
"name": "react-shortcut", | ||
"version": "1.0.6", | ||
"description": "Easily add global hotkeys to your React app", | ||
"main": "src/Component.js", | ||
"version": "2.0.7", | ||
"description": "Convenient React component that detects if the given key combination is pressed, and triggers a callback", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"homepage": "https://github.com/devlato/react-shortcut", | ||
"bugs": { | ||
"url": "https://github.com/devlato/react-shortcut/issues" | ||
}, | ||
"scripts": { | ||
"test": "NODE_ENV=test jest -u --no-cache --config .jestrc", | ||
"test:coverage": "NODE_ENV=test jest --coverage --no-cache --config .jestrc", | ||
"lint": "eslint --config .eslintrc --ext .js .", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls", | ||
"codeclimate": "cat ./coverage/lcov.info | codeclimate-test-reporter", | ||
"test:report": "npm run coveralls && npm run codeclimate", | ||
"validate": "npm run lint && npm run test:coverage", | ||
"prepush": "npm run validate" | ||
"format": "prettier --write src .jest", | ||
"lint": "eslint --ext .ts,.tsx,.js,.jsx,.json -c .eslintrc.js .", | ||
"test": "cross-env NODE_ENV=test jest", | ||
"test:ci": "npm run clean:coverage && cross-env NODE_ENV=test jest --coverage", | ||
"clean:build": "rimraf dist", | ||
"clean:coverage": "rimraf coverage", | ||
"clean:storybook": "rimraf docs", | ||
"clean": "npm run clean:build & npm run clean:coverage & npm run clean:storybook && wait", | ||
"build:code": "cross-env NODE_ENV=production rollup -c rollup.config.js", | ||
"build": "npm run clean:build && npm run build:code", | ||
"storybook": "cross-env NODE_ENV=development start-storybook -p 6006 -c .storybook", | ||
"storybook:compile": "cross-env NODE_ENV=production build-storybook -c .storybook -o docs", | ||
"storybook:build": "npm run clean:storybook && npm run storybook:compile", | ||
"pre-push": "npm run lint && npm run test:coverage", | ||
"prepublish": "npm run clean && npm run build" | ||
}, | ||
"lint-staged": { | ||
"src/**/*.{ts,tsx,js,jsx,json}": ["eslint -c ./.eslintrc.js --fix", "jest —-bail --color --findRelatedTests"], | ||
"./*.{ts,tsx,js,jsx,json}": ["eslint -c ./.eslintrc.js --fix", "jest —-bail --color --findRelatedTests"] | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged", | ||
"pre-push": "npm run lint && npm run test && npm run build" | ||
} | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/devlato/react-hotkeys.git" | ||
"url": "git+https://github.com/devlato/react-shortcut.git" | ||
}, | ||
"keywords": [ | ||
"react", | ||
"hotkeys", | ||
"hotkey", | ||
"shortcut", | ||
"keyboard", | ||
"keydown", | ||
"listener", | ||
"keypress" | ||
], | ||
"author": "devlato <npm@devlato.com> (http://devlato.com/)", | ||
"keywords": ["react", "component", "library", "typescript", "hotkeys", "hotkey", "shortcut", "keyboard"], | ||
"author": "devlato <npm@devlato.com> (https://devlato.com/)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/devlato/react-hotkeys/issues" | ||
}, | ||
"homepage": "https://github.com/devlato/react-hotkeys#readme", | ||
"files": [ | ||
"package.json", | ||
"README.md", | ||
".gitignore", | ||
".editorconfig", | ||
"src" | ||
], | ||
"files": ["package.json", "README.md", "LICENSE", "dist"], | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"codeclimate-test-reporter": "0.4.0", | ||
"coveralls": "2.11.15", | ||
"enzyme": "^2.7.1", | ||
"eslint": "3.14.1", | ||
"eslint-config-airbnb-base": "11.0.1", | ||
"eslint-plugin-import": "2.2.0", | ||
"husky": "0.13.1", | ||
"jest": "^19.0.2", | ||
"react-addons-test-utils": "^15.4.2", | ||
"sinon": "^1.17.7" | ||
"@babel/core": "^7.9.0", | ||
"@babel/preset-env": "^7.9.0", | ||
"@babel/preset-react": "^7.9.4", | ||
"@rollup/plugin-node-resolve": "^7.1.1", | ||
"@storybook/addon-actions": "^5.3.17", | ||
"@storybook/addon-knobs": "^5.3.17", | ||
"@storybook/addons": "^5.3.17", | ||
"@storybook/cli": "^5.3.17", | ||
"@storybook/preset-typescript": "^3.0.0", | ||
"@storybook/react": "^5.3.17", | ||
"@types/enzyme": "^3.10.4", | ||
"@types/jest": "^24.0.23", | ||
"@types/mousetrap": "^1.6.3", | ||
"@types/node": "^12.12.17", | ||
"@types/prettier": "^1.19.1", | ||
"@types/react": "^16.9.16", | ||
"@types/react-dom": "^16.9.4", | ||
"@typescript-eslint/eslint-plugin": "^2.12.0", | ||
"@typescript-eslint/parser": "^2.12.0", | ||
"babel-loader": "^8.1.0", | ||
"brotli": "^1.3.2", | ||
"coveralls": "^3.0.11", | ||
"cross-env": "^7.0.2", | ||
"enzyme": "^3.11.0", | ||
"enzyme-adapter-react-16": "^1.15.2", | ||
"enzyme-to-json": "^3.4.4", | ||
"eslint": "^6.8.0", | ||
"eslint-config-prettier": "^6.10.1", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"eslint-plugin-react": "^7.19.0", | ||
"husky": "^4.2.3", | ||
"jest": "^25.2.3", | ||
"lint-staged": "^10.0.9", | ||
"prettier": "^2.0.2", | ||
"react": "*", | ||
"react-dom": "*", | ||
"rimraf": "^3.0.2", | ||
"rollup": "^2.2.0", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
"rollup-plugin-gzip": "^2.3.0", | ||
"rollup-plugin-terser": "^5.3.0", | ||
"rollup-plugin-typescript2": "^0.27.0", | ||
"ts-jest": "^25.2.1", | ||
"ts-loader": "^6.2.2", | ||
"ts-node": "^8.8.1", | ||
"typescript": "^3.8.3" | ||
}, | ||
"dependencies": { | ||
"bluebird": "3.4.7", | ||
"lodash": "^4.17.4", | ||
"react": "15.4.2", | ||
"react-dom": "^15.4.2" | ||
"peerDependencies": { | ||
"react": "*", | ||
"react-dom": "*" | ||
}, | ||
"engines": { | ||
"node": ">= 4", | ||
"npm": ">= 2" | ||
"node": ">= 8", | ||
"npm": ">= 4" | ||
}, | ||
"dependencies": { | ||
"mousetrap": "^1.6.5" | ||
} | ||
} |
229
README.md
@@ -1,13 +0,16 @@ | ||
# react-shortcut | ||
# ReactShortcut | ||
Easily add global hotkeys/shortcuts to your React app | ||
Convenient React component that detects if the given key combination is pressed, and triggers a callback | ||
[![View on npm](https://badge.fury.io/js/react-shortcut.svg)](https://npmjs.org/package/react-shortcut) | ||
[![Master Build Status](https://github.com/devlato/react-shortcut/workflows/CI/badge.svg)](https://github.com/devlato/react-shortcut/actions?query=workflow%3ARelease) | ||
[![Release CI Status](https://github.com/devlato/react-shortcut/workflows/Publish/badge.svg)](https://github.com/devlato/react-shortcut/actions?query=workflow%3APublish) | ||
[![Maintainability](https://api.codeclimate.com/v1/badges/f426b7cb20cd324588ad/maintainability)](https://codeclimate.com/github/devlato/react-shortcut/maintainability) | ||
[![Test Coverage](https://api.codeclimate.com/v1/badges/f426b7cb20cd324588ad/test_coverage)](https://codeclimate.com/github/devlato/react-shortcut/test_coverage) | ||
[![Demo](https://img.shields.io/badge/Live%20Demo-Open-yellow)](https://devlato.github.io/react-shortcut/) | ||
[![Bundle size](https://img.shields.io/bundlephobia/minzip/react-shortcut?label=gzip%20size)](https://npmjs.org/package/react-shortcut) | ||
[![Downloads](https://img.shields.io/npm/dm/react-shortcut)](https://npmjs.org/package/react-shortcut) | ||
[![MIT License](https://img.shields.io/npm/l/react-shortcut)](https://npmjs.org/package/react-shortcut) | ||
[![Issues](https://img.shields.io/github/issues/devlato/react-shortcut)](https://github.com/devlato/react-shortcut/issues) | ||
[![Build Status](https://travis-ci.org/devlato/react-hotkeys.svg?branch=master)](https://travis-ci.org/devlato/react-hotkeys) | ||
[![Coverage Status](https://coveralls.io/repos/github/devlato/react-hotkeys/badge.svg?branch=master)](https://coveralls.io/github/devlato/react-hotkeys?branch=master) | ||
[![Code Climate](https://codeclimate.com/github/devlato/react-hotkeys/badges/gpa.svg)](https://codeclimate.com/github/devlato/react-hotkeys) | ||
[![Issue Count](https://codeclimate.com/github/devlato/react-hotkeys/badges/issue_count.svg)](https://codeclimate.com/github/devlato/react-hotkeys) | ||
[![npm version](https://badge.fury.io/js/react-shortcut.svg)](https://badge.fury.io/js/react-shortcut) | ||
## Installation | ||
@@ -27,168 +30,140 @@ | ||
## Using the component | ||
## Usage | ||
Is very simple and straightforward! There are just a couple of props to pass in. | ||
The usage is very simple, there is just a couple of props to pass. | ||
### Code example | ||
```jsx | ||
const HotKey = require('react-shortcut'); | ||
```typescript jsx | ||
import ReactShortcut from 'react-shortcut'; | ||
// ... | ||
render() { | ||
return ( | ||
<HotKey | ||
keys={/* Array of hotkeys */} | ||
simultaneous={/* Add this prop if keys should be pressed all together */} | ||
onKeysCoincide={/* Callback when target key combination is pressed */} | ||
/> | ||
); | ||
} | ||
// Somewhere in your component tree | ||
<ReactShortcut | ||
keys={/* String or array of strings containing the keys to be pressed, in any supported format */} | ||
onKeysPressed={/* Callback when target key combination is pressed */} | ||
/>; | ||
``` | ||
You can add `react-shortcut` anywhere in your component hierarchy, because it adds a global | ||
keyboard events listener and doesn't stops any event bubbling. | ||
### Props | ||
For example: | ||
All the props are required. | ||
```jsx | ||
const HotKey = require('react-shortcut'); | ||
| Name | Description | Type | | ||
| --------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------- | | ||
| `keys` | A string containing comma-separated key combinations or/and key sequences, or an array of such strings | A string or an array of strings | | ||
| `onKeysPressed` | A callback to be triggered when the user presses any of the specified key combinations | A function with no arguments | | ||
const React = require('react'); | ||
const Menu = require('menu/Menu'); // Just an example | ||
const MenuItem = require('menu/MenuItem'); // Just an example | ||
### Key combinations and Key sequences | ||
The component supports both **key combinations** and **key sequences**. | ||
export default class AnyYourComponent extends React.Component { | ||
static propTypes = { | ||
showOpenFileDialog: React.PropTypes.fn.isRequired | ||
}; | ||
#### Key combinations | ||
A **key combination** is a string of key names separated by a plus sign, that describes what keys the user has to press at the same time, to execute the callback specified using `onKeysPressed` prop. | ||
render() { | ||
const openFileKeys = ['ctrl', 'o']; | ||
Examples: `Command+Shift+Left`, `Ctrl+P`. | ||
return ( | ||
<Menu> | ||
<MenuItem | ||
label="Open File" | ||
onClick={this.onFileOpen} | ||
/> | ||
</Menu> | ||
<HotKey | ||
keys={openFileKeys} | ||
simultaneous | ||
onKeysCoincide={this.onFileOpen} | ||
/> | ||
); | ||
} | ||
To react on the keys combination(s) press, use the following format: | ||
```typescript jsx | ||
import ReactShortcut from 'react-shortcut'; | ||
onFileOpen() { | ||
const {showOpenFileDialog} = this.props; | ||
// Pass in the shortcut keys | ||
<ReactShortcut | ||
keys="command+k" | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
showOpenFileDialog(); | ||
} | ||
} | ||
// ... or an array of shortcuts | ||
<ReactShortcut | ||
keys={['command+k', 'command+m']} | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
// ... or a string of comma-separated shortcuts | ||
<ReactShortcut | ||
keys="command+k,command+m" | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
``` | ||
#### Key sequences | ||
## Props | ||
A **key sequence** is a string of key names separated by a space character, that lists out the keys the user has to press one by one, to trigger the callback specified using `onKeysPressed` prop. | ||
* `keys` – Just array of string representing each button to be pressed; | ||
* `simultaneous` – Set this prop if user should press buttons all together; | ||
* `onKeysCoincide` – Callback function to be called when user pressed the target buttons. | ||
Examples: `Up Up Down Down Left Right Left Right B A Enter`, `k o n a m i`. | ||
To react on the keys sequence(s) press, use the following format: | ||
## Supported keys | ||
```typescript jsx | ||
import ReactShortcut from 'react-shortcut'; | ||
All alphabetic letters and numbers could be passed as is, i.e. letter "a" is just "a". | ||
// Pass in the shortcut keys | ||
<ReactShortcut | ||
keys="k o n a m i" | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
If you use `simultaneous` mode and you have the `Shift` button in your hotkey combination, | ||
please set the unmodified buttons. | ||
// ... or an array of shortcuts | ||
<ReactShortcut | ||
keys={['k o n a m i', 'm a r i o b r o s enter']} | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
For example, to have a `Shift+!` hotkey, you should pass `keys={["shift", "1"]}`, | ||
because "Shift" and "1" pressed together produce "!". | ||
// ... or a string of comma-separated shortcuts | ||
<ReactShortcut | ||
keys="k o n a m i,m a r i o b r o s enter" | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
``` | ||
#### Mixed use | ||
## Examples of react-shortcut usage | ||
Mixing both modes is possible –just follow the same key combination/key sequence convention: | ||
* [react-easter](https://www.npmjs.com/package/react-easter) – Easily add Easter eggs to your React app | ||
```typescript jsx | ||
import ReactShortcut from 'react-shortcut'; | ||
// Array of shortcuts | ||
<ReactShortcut | ||
keys={['k o n a m i', 'shift+command+m']} | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
## Test coverage | ||
Library has ~100% test coverage: | ||
```sh | ||
$ npm run test:coverage | ||
> react-shortcut@1.0.0 test:coverage ~/projects/react-shortcut | ||
> NODE_ENV=test jest --coverage --no-cache --config .jestrc | ||
PASS test/Component.js | ||
<HotKey /> | ||
✓ Calls componentDidMount (19ms) | ||
✓ Should handle keys sequently (11ms) | ||
✓ Should not react to events without keys (3ms) | ||
✓ Should not react if empty keys passed (515ms) | ||
✓ Should remove listener on unmount (4ms) | ||
--------------|----------|----------|----------|----------|----------------| | ||
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | | ||
--------------|----------|----------|----------|----------|----------------| | ||
All files | 100 | 85.29 | 100 | 100 | | | ||
Component.js | 100 | 85.29 | 100 | 100 | | | ||
--------------|----------|----------|----------|----------|----------------| | ||
Test Suites: 1 passed, 1 total | ||
Tests: 5 passed, 5 total | ||
Snapshots: 0 total | ||
Time: 2.032s | ||
Ran all test suites. | ||
// ... or a string of comma-separated shortcuts | ||
<ReactShortcut | ||
keys="k o n a m i,shift+command+m" | ||
onKeysPressed={doSomethingOnShortcutPress} | ||
/> | ||
``` | ||
## FAQ | ||
## Code style | ||
### Does it support TypeScript? | ||
Library is 100% compatible with [airbnb-base](https://www.npmjs.com/package/eslint-config-airbnb-base) for ES5. | ||
It does. Moreover, it's implemented in TypeScript. | ||
### Do I have to use <ReactShortcut /> component only in the root level component? | ||
## Available commands | ||
Nope. The component adds a global keyboard event listener and doesn't prevent events from bubbling or capturing. | ||
Library has the following commands available: | ||
### What if my app needs to support multiple shortcuts? | ||
* Run the tests: | ||
Just use the component as many times as you need, just make sure the shortcuts aren't repeated. | ||
``` | ||
$ npm test | ||
``` | ||
### Do I have to specify the shortcuts in lower case only? | ||
* Run the tests and display test coverage: | ||
No, the case doesn't matter. | ||
``` | ||
$ npm run test:coverage | ||
``` | ||
### Any open-source examples of using this library? | ||
* Run the linter: | ||
There's an official™️ one called [react-easter](https://www.npmjs.com/package/react-easter), for adding easter eggs triggered by the keypress. | ||
``` | ||
$ npm run lint | ||
``` | ||
## Build | ||
No building required, library is implemented with ES5 React syntax for better compatibility and shipped as is. | ||
## License | ||
Library is shipped "as is" under MIT License. | ||
The library is shipped "as is" under MIT License. | ||
## Contributing [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/devlato/react-shortcut/issues) | ||
## Contributing | ||
Feel free to contribute but don't forget to test everything properly. | ||
[![NPM](https://nodei.co/npm/react-shortcut.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/react-shortcut/) | ||
Feel free to contribute, but don't forget to write tests, mate/matess. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
66842
3
8
46
54
1
169
1
+ Addedmousetrap@^1.6.5
+ Addedmousetrap@1.6.5(transitive)
+ Addedreact@18.3.1(transitive)
+ Addedreact-dom@18.3.1(transitive)
+ Addedscheduler@0.23.2(transitive)
- Removedbluebird@3.4.7
- Removedlodash@^4.17.4
- Removedreact@15.4.2
- Removedreact-dom@^15.4.2
- Removedasap@2.0.6(transitive)
- Removedbluebird@3.4.7(transitive)
- Removedcore-js@1.2.7(transitive)
- Removedcreate-react-class@15.7.0(transitive)
- Removedencoding@0.1.13(transitive)
- Removedfbjs@0.8.18(transitive)
- Removediconv-lite@0.6.3(transitive)
- Removedis-stream@1.1.0(transitive)
- Removedisomorphic-fetch@2.2.1(transitive)
- Removedlodash@4.17.21(transitive)
- Removednode-fetch@1.7.3(transitive)
- Removedobject-assign@4.1.1(transitive)
- Removedpromise@7.3.1(transitive)
- Removedprop-types@15.8.1(transitive)
- Removedreact@15.4.215.7.0(transitive)
- Removedreact-dom@15.7.0(transitive)
- Removedreact-is@16.13.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsetimmediate@1.0.5(transitive)
- Removedua-parser-js@0.7.38(transitive)
- Removedwhatwg-fetch@3.6.20(transitive)