@vgerbot/shortcuts
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

@vgerbot/shortcuts

Test CodeQL Codacy Badge Codacy Badge code style: prettier npm bundle size (scoped)

🔌 Install

Using npm/yarn

$ npm i @vgerbot/shortcuts
$ # or
$ yarn add @vgerbot/shortcuts

Then import/require the module:

const { } = require('@vgerbot/shortcuts');
// or
import { } from '@vgerbot/shortcuts';

Using CDN

  1. jsDelivr:

    <script src="//cdn.jsdelivr.net/npm/@vgerbot/shortcuts/lib/index.min.js"></script>
  2. unpkg

    <script src="//unpkg.com/@vgerbot/shortcuts/lib/index.min.js"></script>

Then:

<script>
    const {} = Shortcuts;
</script>

📚 Usage

Pattern matching

import { match } from '@vgerbot/shortcuts';
const matcher = match
    .case('Ctrl+A', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}`)) // output when matching: Pressed 'Ctrl+A'
    .case('Mod+Z', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}'`)) // output when matching: Mac: `Pressed 'Meta+A'`, Win,Linux:`Pressed 'Ctrl+A'`
    .case('Ctrl+P|Shift+Ctrl+P', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}`)) // output when matching: `Pressed 'Ctrl+P'` or `Pressed 'Shift+Ctrl+P'`
    ;
document.body.addEventListener('keydown', e => {
    matcher(e);
})

You may omit .case.

import { match } from '@vgerbot/shortcuts';
const matcher = match('Ctrl+A', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}`)) // output when matching: Pressed 'Ctrl+A'
    ('Mod+Z', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}'`)) // output when matching: Mac: `Pressed 'Meta+A'`, Win,Linux:`Pressed 'Ctrl+A'`
    ('Ctrl+P|Shift+Ctrl+P', (shortcutEvent) => console.log(`Pressed '${shortcutEvent.shortcut}`)) // output when matching: `Pressed 'Ctrl+P'` or `Pressed 'Shift+Ctrl+P'`
    ;
document.body.addEventListener('keydown', e => {
  matcher(e);
})

The result of the callback will be returned from matcher.

import { match } from '@vgerbot/shortcuts';
const matcher =
    match('Ctrl+A', () => 'A')
    ('Ctrl+B', () => 'B')
document.body.addEventListener('keydown', e => {
  const result = matcher(e);
  console.log(result); // If there is no match, `undefined` will be returned.
})

If you provide a value instead of a function, that value will be returnd

import { match } from '@vgerbot/shortcuts';
const matcher =
    match('Ctrl+A', 'A')
    ('Ctrl+B', 'B')
document.body.addEventListener('keydown', e => {
  const result = matcher(e);
  console.log(result);  // If there is no match, `undefined` will be returned.
})

You may use the .else to define a callback if no shortcut pattern matches.

import { match } from '@vgerbot/shortcuts';
const matcher =
    match('Ctrl+A', 'A')
    ('Ctrl+B', 'B')
    .else(() => console.log('no shortcut pattern matches'));
document.body.addEventListener('keydown', e => {
  matcher(e);
})

Keymap configuration

import { Keyboard } from '@vgerbot/shortcuts';
const keyboard = new Keyboard();
keyboard.keymap({
  commands: {
    copy: {
      shortcut: 'Ctrl+C',
      preventDefault: true
    },
    paste: {
      shortcut: 'Ctrl+V',
      preventDefault: true
    },
    print: 'Ctrl+P',
    find: 'Ctrl+F',
    replace: 'Ctrl+H',
    devtool: 'F12',
    close: 'Ctrl+W',
    confirm: {
      shortcut: 'Enter',
      interceptors: [
        (event, next) => {
          if(event.target.nodeName === 'INPUT') {
            return;
          }
          next(event);
        }
      ]
    }
  },
  contexts: {
    default: {
      commands: ['devtool', 'print']
    },
    closable: {
      abstract: true,
      commands: ['close']
    },
    searchable: {
      abstract: true,
      commands: ['find', 'replace']
    },
    editor: {
      commands: ['copy', 'paste'],
      fallbacks: ['closable', 'searchable']
    },
    previewer: {
      commands: ['print'],
      fallbacks: ['searchable']
    },
    dialog: {
      commands: ['confirm'],
      fallbacks: ['closable']
    }
  }
})

With the keymap method, we can easily override existing shortcut commands:

keyboard.keymap({
    commands: {
        copy: {
            shortcut: 'Ctrl+Alt+C'
        }
    }
})

This feature is useful for applications that require custom shortcut keys.

Shortcut context

Now that we have everything configured, next we listen for keyboard events with the command name as the event name as shown below:

keyboard.on('close', () => {
    console.log('close');
})

However, it does not work now because there is no 'close' command for the current context. The event can only be responded to if the currently activated context keymap configuration contains the 'close' command.

keyboard.switchContext('editor');

When the user presses Ctrl+W, the close event will be executed. When the context is switched to previewer, since previewer does not have a close command, the user presses Ctrl+W and the event is no longer triggered.

Fallback context

If a shortcut command is not found in current activated context, by default, the shortcuts will look for same command in default context, but if some context has been specified a fallback context, the shortcuts will look for that fallback context first.

Shortcut macros

import { Keyboard, macros } from '@vgerbot/shortcuts';
const keyboard = new Keyboard();
// These following defines the macros globally.
macros('Mod', isMac ? 'Meta' : 'Ctrl');
macros('Cs', e => {
    return e.crlKey && e.shifKey;
});
// or defines the macros for keyboard instance.
keyboard.macros('Mod', isMac ? 'Meta' : 'Ctrl');
keyboard.macros('Cs', e => {
    return e.crlKey && e.shifKey;
});
// After that, you can use macros like this:
keyboard.keymap({
    commands: {
        copy: 'Mod+C', // On Mac OS, it is equivalent to Meta+C, and other systems are equivalent to Ctrl+C
        capture: 'Cs+A' // Equivalent to Ctrl+Shift+A
    }
})

Package Sidebar

Install

npm i @vgerbot/shortcuts

Weekly Downloads

1

Version

1.0.0

License

MIT

Unpacked Size

492 kB

Total Files

45

Last publish

Collaborators

  • y1j2x34