UNPKG

slate-hotkeys

Version:

A set of function to detect common keypresses in a platform-agnostic way

597 lines (498 loc) 14.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.SlateHotkeys = {}))); }(this, (function (exports) { 'use strict'; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var lib = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Constants. */ var IS_MAC = typeof window != 'undefined' && /Mac|iPod|iPhone|iPad/.test(window.navigator.platform); var MODIFIERS = { alt: 'altKey', control: 'ctrlKey', meta: 'metaKey', shift: 'shiftKey' }; var ALIASES = { add: '+', break: 'pause', cmd: 'meta', command: 'meta', ctl: 'control', ctrl: 'control', del: 'delete', down: 'arrowdown', esc: 'escape', ins: 'insert', left: 'arrowleft', mod: IS_MAC ? 'meta' : 'control', opt: 'alt', option: 'alt', return: 'enter', right: 'arrowright', space: ' ', spacebar: ' ', up: 'arrowup', win: 'meta', windows: 'meta' }; var CODES = { backspace: 8, tab: 9, enter: 13, shift: 16, control: 17, alt: 18, pause: 19, capslock: 20, escape: 27, ' ': 32, pageup: 33, pagedown: 34, end: 35, home: 36, arrowleft: 37, arrowup: 38, arrowright: 39, arrowdown: 40, insert: 45, delete: 46, meta: 91, numlock: 144, scrolllock: 145, ';': 186, '=': 187, ',': 188, '-': 189, '.': 190, '/': 191, '`': 192, '[': 219, '\\': 220, ']': 221, '\'': 222 }; for (var f = 1; f < 20; f++) { CODES['f' + f] = 111 + f; } /** * Is hotkey? */ function isHotkey(hotkey, options, event) { if (options && !('byKey' in options)) { event = options; options = null; } if (!Array.isArray(hotkey)) { hotkey = [hotkey]; } var array = hotkey.map(function (string) { return parseHotkey(string, options); }); var check = function check(e) { return array.some(function (object) { return compareHotkey(object, e); }); }; var ret = event == null ? check : check(event); return ret; } function isCodeHotkey(hotkey, event) { return isHotkey(hotkey, event); } function isKeyHotkey(hotkey, event) { return isHotkey(hotkey, { byKey: true }, event); } /** * Parse. */ function parseHotkey(hotkey, options) { var byKey = options && options.byKey; var ret = {}; // Special case to handle the `+` key since we use it as a separator. hotkey = hotkey.replace('++', '+add'); var values = hotkey.split('+'); var length = values.length; // Ensure that all the modifiers are set to false unless the hotkey has them. for (var k in MODIFIERS) { ret[MODIFIERS[k]] = false; } var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = values[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var value = _step.value; var optional = value.endsWith('?'); if (optional) { value = value.slice(0, -1); } var name = toKeyName(value); var modifier = MODIFIERS[name]; if (length === 1 || !modifier) { if (byKey) { ret.key = name; } else { ret.which = toKeyCode(value); } } if (modifier) { ret[modifier] = optional ? null : true; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return ret; } /** * Compare. */ function compareHotkey(object, event) { for (var key in object) { var expected = object[key]; var actual = void 0; if (expected == null) { continue; } if (key === 'key') { actual = event.key.toLowerCase(); } else if (key === 'which') { actual = expected === 91 && event.which === 93 ? 91 : event.which; } else { actual = event[key]; } if (actual == null && expected === false) { continue; } if (actual !== expected) { return false; } } return true; } /** * Utils. */ function toKeyCode(name) { name = toKeyName(name); var code = CODES[name] || name.toUpperCase().charCodeAt(0); return code; } function toKeyName(name) { name = name.toLowerCase(); name = ALIASES[name] || name; return name; } /** * Export. */ exports.default = isHotkey; exports.isHotkey = isHotkey; exports.isCodeHotkey = isCodeHotkey; exports.isKeyHotkey = isKeyHotkey; exports.parseHotkey = parseHotkey; exports.compareHotkey = compareHotkey; exports.toKeyCode = toKeyCode; exports.toKeyName = toKeyName; }); unwrapExports(lib); var lib_1 = lib.isHotkey; var lib_2 = lib.isCodeHotkey; var lib_3 = lib.isKeyHotkey; var lib_4 = lib.parseHotkey; var lib_5 = lib.compareHotkey; var lib_6 = lib.toKeyCode; var lib_7 = lib.toKeyName; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var isBrowser = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && (typeof document === "undefined" ? "undefined" : _typeof(document)) === 'object' && document.nodeType === 9; var slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /** * Browser matching rules. * * @type {Array} */ var BROWSER_RULES = [['edge', /Edge\/([0-9\._]+)/], ['chrome', /(?!Chrom.*OPR)Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/], ['firefox', /Firefox\/([0-9\.]+)(?:\s|$)/], ['opera', /Opera\/([0-9\.]+)(?:\s|$)/], ['opera', /OPR\/([0-9\.]+)(:?\s|$)$/], ['ie', /Trident\/7\.0.*rv\:([0-9\.]+)\).*Gecko$/], ['ie', /MSIE\s([0-9\.]+);.*Trident\/[4-7].0/], ['ie', /MSIE\s(7\.0)/], ['android', /Android\s([0-9\.]+)/], ['safari', /Version\/([0-9\._]+).*Safari/]]; if (isBrowser) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = BROWSER_RULES[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _ref = _step.value; var _ref2 = slicedToArray(_ref, 2); var name = _ref2[0]; var regexp = _ref2[1]; if (regexp.test(window.navigator.userAgent)) { break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } /** * Operating system matching rules. * * @type {Array} */ var OS_RULES = [['ios', /os ([\.\_\d]+) like mac os/i], // must be before the macos rule ['macos', /mac os x/i], ['android', /android/i], ['firefoxos', /mozilla\/[a-z\.\_\d]+ \((?:mobile)|(?:tablet)/i], ['windows', /windows\s*(?:nt)?\s*([\.\_\d]+)/i]]; var os = void 0; if (isBrowser) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = OS_RULES[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _ref3 = _step2.value; var _ref4 = slicedToArray(_ref3, 2); var _name = _ref4[0]; var _regexp = _ref4[1]; if (_regexp.test(window.navigator.userAgent)) { os = _name; break; } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } /** * Feature matching rules. * * @type {Array} */ var FEATURE_RULES = [['inputeventslevel1', function (window) { var event = window.InputEvent ? new window.InputEvent('input') : {}; var support = 'inputType' in event; return support; }], ['inputeventslevel2', function (window) { var element = window.document.createElement('div'); element.contentEditable = true; var support = 'onbeforeinput' in element; return support; }]]; var features = []; if (isBrowser) { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = FEATURE_RULES[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var _ref5 = _step3.value; var _ref6 = slicedToArray(_ref5, 2); var _name2 = _ref6[0]; var test = _ref6[1]; if (test(window)) { features.push(_name2); } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } /** * Array of regular expression matchers and their API version * * @type {Array} */ var ANDROID_API_VERSIONS = [[/^9([.]0|)/, 28], [/^8[.]1/, 27], [/^8([.]0|)/, 26], [/^7[.]1/, 25], [/^7([.]0|)/, 24], [/^6([.]0|)/, 23], [/^5[.]1/, 22], [/^5([.]0|)/, 21], [/^4[.]4/, 20]]; /** * get the Android API version from the userAgent * * @return {number} version */ function getAndroidApiVersion() { if (os !== 'android') return null; var userAgent = window.navigator.userAgent; var matchData = userAgent.match(/Android\s([0-9\.]+)/); if (matchData == null) return null; var versionString = matchData[1]; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = ANDROID_API_VERSIONS[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _ref7 = _step4.value; var _ref8 = slicedToArray(_ref7, 2); var regex = _ref8[0]; var version = _ref8[1]; if (versionString.match(regex)) return version; } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } return null; } var IS_ANDROID = os === 'android'; var IS_IOS = os === 'ios'; var IS_MAC = os === 'macos'; var ANDROID_API_VERSION = getAndroidApiVersion(); var HAS_INPUT_EVENTS_LEVEL_1 = features.includes('inputeventslevel1'); var HAS_INPUT_EVENTS_LEVEL_2 = features.includes('inputeventslevel2') || IS_ANDROID && (ANDROID_API_VERSION === 28 || ANDROID_API_VERSION === null); /** * Hotkey mappings for each platform. * * @type {Object} */ var HOTKEYS = { bold: 'mod+b', compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'], moveBackward: 'left', moveForward: 'right', moveWordBackward: 'ctrl+left', moveWordForward: 'ctrl+right', deleteBackward: 'shift?+backspace', deleteForward: 'shift?+delete', extendBackward: 'shift+left', extendForward: 'shift+right', italic: 'mod+i', splitBlock: 'shift?+enter', undo: 'mod+z' }; var APPLE_HOTKEYS = { moveLineBackward: 'opt+up', moveLineForward: 'opt+down', moveWordBackward: 'opt+left', moveWordForward: 'opt+right', deleteBackward: ['ctrl+backspace', 'ctrl+h'], deleteForward: ['ctrl+delete', 'ctrl+d'], deleteLineBackward: 'cmd+shift?+backspace', deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'], deleteWordBackward: 'opt+shift?+backspace', deleteWordForward: 'opt+shift?+delete', extendLineBackward: 'opt+shift+up', extendLineForward: 'opt+shift+down', redo: 'cmd+shift+z', transposeCharacter: 'ctrl+t' }; var WINDOWS_HOTKEYS = { deleteWordBackward: 'ctrl+shift?+backspace', deleteWordForward: 'ctrl+shift?+delete', redo: 'ctrl+y' /** * Hotkeys. * * @type {Object} */ };var Hotkeys = {}; var IS_APPLE = IS_IOS || IS_MAC; var IS_WINDOWS$1 = !IS_APPLE; var KEYS = [].concat(Object.keys(HOTKEYS)).concat(Object.keys(APPLE_HOTKEYS)).concat(Object.keys(WINDOWS_HOTKEYS)); KEYS.forEach(function (key) { var method = 'is' + key[0].toUpperCase() + key.slice(1); if (Hotkeys[method]) return; var generic = HOTKEYS[key]; var apple = APPLE_HOTKEYS[key]; var windows = WINDOWS_HOTKEYS[key]; var isGeneric = generic && lib_3(generic); var isApple = apple && lib_3(apple); var isWindows = windows && lib_3(windows); Hotkeys[method] = function (event) { if (isGeneric && isGeneric(event)) return true; if (IS_APPLE && isApple && isApple(event)) return true; if (IS_WINDOWS$1 && isWindows && isWindows(event)) return true; return false; }; }); exports.default = Hotkeys; Object.defineProperty(exports, '__esModule', { value: true }); })));