diff --git a/__mocks__/react-native-key-command.js b/__mocks__/react-native-key-command.js
deleted file mode 100644
index 092ab120a142..000000000000
--- a/__mocks__/react-native-key-command.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const registerKeyCommands = () => {};
-const unregisterKeyCommands = () => {};
-const constants = {};
-const eventEmitter = () => {};
-const addListener = () => {};
-
-export {
- registerKeyCommands,
- unregisterKeyCommands,
- constants,
- eventEmitter,
- addListener,
-};
diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java
index 3e6381000409..bd90ee9abd02 100644
--- a/android/app/src/main/java/com/expensify/chat/MainActivity.java
+++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java
@@ -2,9 +2,7 @@
import android.os.Bundle;
import android.content.pm.ActivityInfo;
-import android.view.KeyEvent;
import com.expensify.chat.bootsplash.BootSplash;
-import com.expensify.reactnativekeycommand.KeyCommandModule;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
@@ -46,34 +44,4 @@ protected void onCreate(Bundle savedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
-
- /**
- * This method is called when a key down event has occurred.
- * Forwards the event to the KeyCommandModule
- */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) {
- return false;
- }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyLongPress(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyUp(keyCode, event);
- }
-}
+}
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 86707162d74c..28de3a7fa527 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -514,8 +514,6 @@ PODS:
- React
- react-native-image-picker (5.1.0):
- React-Core
- - react-native-key-command (0.9.1):
- - React-Core
- react-native-netinfo (8.3.1):
- React-Core
- react-native-pdf (6.6.2):
@@ -767,7 +765,6 @@ DEPENDENCIES:
- react-native-flipper (from `../node_modules/react-native-flipper`)
- "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)"
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- - react-native-key-command (from `../node_modules/react-native-key-command`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-pdf (from `../node_modules/react-native-pdf`)
- react-native-performance (from `../node_modules/react-native-performance`)
@@ -919,8 +916,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@oguzhnatly/react-native-image-manipulator"
react-native-image-picker:
:path: "../node_modules/react-native-image-picker"
- react-native-key-command:
- :path: "../node_modules/react-native-key-command"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-pdf:
@@ -1007,7 +1002,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Airship: 19ead2c0bdc791c1b9d6ebb7940aaac99614414e
AirshipFrameworkProxy: 037a0ad6491757c45de2c70a6cc47bae5fcfa32b
- boost: a7c83b31436843459a1961bfd74b96033dc77234
+ boost: 57d2868c099736d80fcd648bf211b4431e51a558
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f
@@ -1050,7 +1045,7 @@ SPEC CHECKSUMS:
Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4
Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
- RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
+ RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be
RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30
React: a71c8e1380f07e01de721ccd52bcf9c03e81867d
@@ -1072,7 +1067,6 @@ SPEC CHECKSUMS:
react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4
react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56
react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b
- react-native-key-command: e49d6e44d44705779696d8d3a5ac6b9e3a198941
react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658
react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa
react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406
diff --git a/package-lock.json b/package-lock.json
index 859535dd75e9..e1ae5097ae43 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -70,7 +70,6 @@
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
"react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972",
- "react-native-key-command": "^0.9.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "1.0.38",
@@ -34671,21 +34670,6 @@
"integrity": "sha512-jNNpW5byieb7pb/l0HRvmCav4BtzpTzgC+ybT+Wbi2yyroOukveVvnjwWnmoOeuGynsYB4Yt5eGrWZnPnJSwqQ==",
"license": "MIT"
},
- "node_modules/react-native-key-command": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.1.tgz",
- "integrity": "sha512-di7G5q66eI0xL14B4kcVfm7azGET07henwu21N8hb71sZpDZGsAJ1WFuR32SwbnkLVNhEk7FJAIH/5Sh+dDQoA==",
- "dependencies": {
- "events": "^3.3.0",
- "underscore": "^1.13.4"
- },
- "peerDependencies": {
- "react": "^18.1.0",
- "react-dom": "18.1.0",
- "react-native": "^0.70.4",
- "react-native-web": "^0.18.1"
- }
- },
"node_modules/react-native-localize": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/react-native-localize/-/react-native-localize-2.2.6.tgz",
@@ -34928,22 +34912,22 @@
}
},
"node_modules/react-native-web": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.1.tgz",
- "integrity": "sha512-kWZKJU/OIvVriC7R7WN2Wpai6QllD9f7RDUuaBj2G9FdXaybSQFgmuhey4n6naqbLnj720im2PtcnH54Cn/UXw==",
+ "version": "0.18.12",
+ "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.12.tgz",
+ "integrity": "sha512-fboP7yqobJ8InSr4fP+bQ3scOtSQtUoPcR+HWasH8b/fk/RO+mWcJs/8n+lewy9WTZc2D68ha7VwRDviUshEWA==",
"peer": true,
"dependencies": {
+ "@babel/runtime": "^7.18.6",
"create-react-class": "^15.7.0",
- "fbjs": "^3.0.0",
- "inline-style-prefixer": "^6.0.0",
+ "fbjs": "^3.0.4",
+ "inline-style-prefixer": "^6.0.1",
"normalize-css-color": "^1.0.2",
"postcss-value-parser": "^4.2.0",
- "prop-types": "^15.6.0",
"styleq": "^0.1.2"
},
"peerDependencies": {
- "react": ">=17.0.2",
- "react-dom": ">=17.0.2"
+ "react": "^17.0.2 || ^18.0.0",
+ "react-dom": "^17.0.2 || ^18.0.0"
}
},
"node_modules/react-native-web-lottie": {
@@ -64350,15 +64334,6 @@
"integrity": "sha512-jNNpW5byieb7pb/l0HRvmCav4BtzpTzgC+ybT+Wbi2yyroOukveVvnjwWnmoOeuGynsYB4Yt5eGrWZnPnJSwqQ==",
"from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972"
},
- "react-native-key-command": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.1.tgz",
- "integrity": "sha512-di7G5q66eI0xL14B4kcVfm7azGET07henwu21N8hb71sZpDZGsAJ1WFuR32SwbnkLVNhEk7FJAIH/5Sh+dDQoA==",
- "requires": {
- "events": "^3.3.0",
- "underscore": "^1.13.4"
- }
- },
"react-native-localize": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/react-native-localize/-/react-native-localize-2.2.6.tgz",
@@ -64495,17 +64470,17 @@
}
},
"react-native-web": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.1.tgz",
- "integrity": "sha512-kWZKJU/OIvVriC7R7WN2Wpai6QllD9f7RDUuaBj2G9FdXaybSQFgmuhey4n6naqbLnj720im2PtcnH54Cn/UXw==",
+ "version": "0.18.12",
+ "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.12.tgz",
+ "integrity": "sha512-fboP7yqobJ8InSr4fP+bQ3scOtSQtUoPcR+HWasH8b/fk/RO+mWcJs/8n+lewy9WTZc2D68ha7VwRDviUshEWA==",
"peer": true,
"requires": {
+ "@babel/runtime": "^7.18.6",
"create-react-class": "^15.7.0",
- "fbjs": "^3.0.0",
- "inline-style-prefixer": "^6.0.0",
+ "fbjs": "^3.0.4",
+ "inline-style-prefixer": "^6.0.1",
"normalize-css-color": "^1.0.2",
"postcss-value-parser": "^4.2.0",
- "prop-types": "^15.6.0",
"styleq": "^0.1.2"
}
},
diff --git a/package.json b/package.json
index 31ba95744a10..73d4acc22e66 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,6 @@
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
"react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972",
- "react-native-key-command": "^0.9.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "1.0.38",
diff --git a/src/CONST.js b/src/CONST.js
index cd53ee9a7461..54bfc6c53fbf 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -1,6 +1,5 @@
import lodashGet from 'lodash/get';
import Config from 'react-native-config';
-import * as KeyCommand from 'react-native-key-command';
import * as Url from './libs/Url';
const CLOUDFRONT_DOMAIN = 'cloudfront.net';
@@ -8,20 +7,10 @@ const CLOUDFRONT_URL = `https://d2k5nsl2zxldvw.${CLOUDFRONT_DOMAIN}`;
const ACTIVE_EXPENSIFY_URL = Url.addTrailingForwardSlash(lodashGet(Config, 'NEW_EXPENSIFY_URL', 'https://new.expensify.com'));
const USE_EXPENSIFY_URL = 'https://use.expensify.com';
const PLATFORM_OS_MACOS = 'Mac OS';
-const PLATFORM_IOS = 'iOS';
const ANDROID_PACKAGE_NAME = 'com.expensify.chat';
const USA_COUNTRY_NAME = 'United States';
const CURRENT_YEAR = new Date().getFullYear();
-const keyModifierControl = lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl');
-const keyModifierCommand = lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand');
-const keyModifierShiftControl = lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl');
-const keyModifierShiftCommand = lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand');
-const keyInputEscape = lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape');
-const keyInputEnter = lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter');
-const keyInputUpArrow = lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow');
-const keyInputDownArrow = lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow');
-
const CONST = {
ANDROID_PACKAGE_NAME,
ANIMATED_TRANSITION: 300,
@@ -234,7 +223,6 @@ const CONST = {
CTRL: {
DEFAULT: 'control',
[PLATFORM_OS_MACOS]: 'meta',
- [PLATFORM_IOS]: 'meta',
},
SHIFT: {
DEFAULT: 'shift',
@@ -245,91 +233,46 @@ const CONST = {
descriptionKey: 'search',
shortcutKey: 'K',
modifiers: ['CTRL'],
- trigger: {
- DEFAULT: {input: 'k', modifierFlags: keyModifierControl},
- [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierCommand},
- [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierCommand},
- },
},
NEW_GROUP: {
descriptionKey: 'newGroup',
shortcutKey: 'K',
modifiers: ['CTRL', 'SHIFT'],
- trigger: {
- DEFAULT: {input: 'k', modifierFlags: keyModifierShiftControl},
- [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierShiftCommand},
- [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierShiftCommand},
- },
},
SHORTCUT_MODAL: {
descriptionKey: 'openShortcutDialog',
shortcutKey: 'I',
modifiers: ['CTRL'],
- trigger: {
- DEFAULT: {input: 'i', modifierFlags: keyModifierControl},
- [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: keyModifierCommand},
- [PLATFORM_IOS]: {input: 'i', modifierFlags: keyModifierCommand},
- },
},
ESCAPE: {
descriptionKey: 'escape',
shortcutKey: 'Escape',
modifiers: [],
- trigger: {
- DEFAULT: {input: keyInputEscape},
- [PLATFORM_OS_MACOS]: {input: keyInputEscape},
- [PLATFORM_IOS]: {input: keyInputEscape},
- },
},
ENTER: {
descriptionKey: null,
shortcutKey: 'Enter',
modifiers: [],
- trigger: {
- DEFAULT: {input: keyInputEnter},
- [PLATFORM_OS_MACOS]: {input: keyInputEnter},
- [PLATFORM_IOS]: {input: keyInputEnter},
- },
},
CTRL_ENTER: {
descriptionKey: null,
shortcutKey: 'Enter',
modifiers: ['CTRL'],
- trigger: {
- DEFAULT: {input: keyInputEnter, modifierFlags: keyModifierControl},
- [PLATFORM_OS_MACOS]: {input: keyInputEnter, modifierFlags: keyModifierCommand},
- [PLATFORM_IOS]: {input: keyInputEnter, modifierFlags: keyModifierCommand},
- },
},
COPY: {
descriptionKey: 'copy',
shortcutKey: 'C',
modifiers: ['CTRL'],
- trigger: {
- DEFAULT: {input: 'c', modifierFlags: keyModifierControl},
- [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: keyModifierCommand},
- [PLATFORM_IOS]: {input: 'c', modifierFlags: keyModifierCommand},
- },
},
ARROW_UP: {
descriptionKey: null,
shortcutKey: 'ArrowUp',
modifiers: [],
- trigger: {
- DEFAULT: {input: keyInputUpArrow},
- [PLATFORM_OS_MACOS]: {input: keyInputUpArrow},
- [PLATFORM_IOS]: {input: keyInputUpArrow},
- },
},
ARROW_DOWN: {
descriptionKey: null,
shortcutKey: 'ArrowDown',
modifiers: [],
- trigger: {
- DEFAULT: {input: keyInputDownArrow},
- [PLATFORM_OS_MACOS]: {input: keyInputDownArrow},
- [PLATFORM_IOS]: {input: keyInputDownArrow},
- },
},
TAB: {
descriptionKey: null,
@@ -837,7 +780,7 @@ const CONST = {
WINDOWS: 'Windows',
MAC_OS: PLATFORM_OS_MACOS,
ANDROID: 'Android',
- IOS: PLATFORM_IOS,
+ IOS: 'iOS',
LINUX: 'Linux',
NATIVE: 'Native',
},
diff --git a/src/components/Button/index.js b/src/components/Button.js
similarity index 93%
rename from src/components/Button/index.js
rename to src/components/Button.js
index 50165ca98774..817a1c1f9e7d 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button.js
@@ -1,20 +1,19 @@
import React, {Component} from 'react';
import {Pressable, ActivityIndicator, View} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import OpacityView from '../OpacityView';
-import Text from '../Text';
-import KeyboardShortcut from '../../libs/KeyboardShortcut';
-import Icon from '../Icon';
-import CONST from '../../CONST';
-import * as StyleUtils from '../../styles/StyleUtils';
-import HapticFeedback from '../../libs/HapticFeedback';
-import withNavigationFallback from '../withNavigationFallback';
-import compose from '../../libs/compose';
-import * as Expensicons from '../Icon/Expensicons';
-import withNavigationFocus from '../withNavigationFocus';
-import validateSubmitShortcut from './validateSubmitShortcut';
+import styles from '../styles/styles';
+import themeColors from '../styles/themes/default';
+import OpacityView from './OpacityView';
+import Text from './Text';
+import KeyboardShortcut from '../libs/KeyboardShortcut';
+import Icon from './Icon';
+import CONST from '../CONST';
+import * as StyleUtils from '../styles/StyleUtils';
+import HapticFeedback from '../libs/HapticFeedback';
+import withNavigationFallback from './withNavigationFallback';
+import compose from '../libs/compose';
+import * as Expensicons from './Icon/Expensicons';
+import withNavigationFocus from './withNavigationFocus';
const propTypes = {
/** The text for the button label */
@@ -158,10 +157,10 @@ class Button extends Component {
// Setup and attach keypress handler for pressing the button with Enter key
this.unsubscribe = KeyboardShortcut.subscribe(shortcutConfig.shortcutKey, (e) => {
- if (!validateSubmitShortcut(this.props.isFocused, this.props.isDisabled, this.props.isLoading, e)) {
+ if (!this.props.isFocused || this.props.isDisabled || this.props.isLoading || (e && e.target.nodeName === 'TEXTAREA')) {
return;
}
-
+ e.preventDefault();
this.props.onPress();
}, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, false, this.props.enterKeyEventListenerPriority, false);
}
diff --git a/src/components/Button/validateSubmitShortcut/index.js b/src/components/Button/validateSubmitShortcut/index.js
deleted file mode 100644
index bfe5c79483fa..000000000000
--- a/src/components/Button/validateSubmitShortcut/index.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Validate if the submit shortcut should be triggered depending on the button state
- *
- * @param {boolean} isFocused Whether Button is on active screen
- * @param {boolean} isDisabled Indicates whether the button should be disabled
- * @param {boolean} isLoading Indicates whether the button should be disabled and in the loading state
- * @param {Object} event Focused input event
- * @returns {boolean} Returns `true` if the shortcut should be triggered
- */
-function validateSubmitShortcut(isFocused, isDisabled, isLoading, event) {
- if (!isFocused || isDisabled || isLoading || (event && event.target.nodeName === 'TEXTAREA')) {
- return false;
- }
-
- event.preventDefault();
- return true;
-}
-
-export default validateSubmitShortcut;
diff --git a/src/components/Button/validateSubmitShortcut/index.native.js b/src/components/Button/validateSubmitShortcut/index.native.js
deleted file mode 100644
index 2822fa56d590..000000000000
--- a/src/components/Button/validateSubmitShortcut/index.native.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Validate if the submit shortcut should be triggered depending on the button state
- *
- * @param {boolean} isFocused Whether Button is on active screen
- * @param {boolean} isDisabled Indicates whether the button should be disabled
- * @param {boolean} isLoading Indicates whether the button should be disabled and in the loading state
- * @returns {boolean} Returns `true` if the shortcut should be triggered
- */
-function validateSubmitShortcut(isFocused, isDisabled, isLoading) {
- if (!isFocused || isDisabled || isLoading) {
- return false;
- }
-
- return true;
-}
-
-export default validateSubmitShortcut;
diff --git a/src/components/KeyboardShortcutsModal.js b/src/components/KeyboardShortcutsModal.js
index a5454e280f0d..81ad2f642831 100644
--- a/src/components/KeyboardShortcutsModal.js
+++ b/src/components/KeyboardShortcutsModal.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {View, ScrollView} from 'react-native';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import HeaderWithCloseButton from './HeaderWithCloseButton';
@@ -34,26 +34,18 @@ const defaultProps = {
class KeyboardShortcutsModal extends React.Component {
componentDidMount() {
- const openShortcutModalConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUT_MODAL;
- this.unsubscribeShortcutModal = KeyboardShortcut.subscribe(openShortcutModalConfig.shortcutKey, () => {
+ const shortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUT_MODAL;
+ this.unsubscribeShortcutModal = KeyboardShortcut.subscribe(shortcutConfig.shortcutKey, () => {
ModalActions.close();
KeyboardShortcutsActions.showKeyboardShortcutModal();
- }, openShortcutModalConfig.descriptionKey, openShortcutModalConfig.modifiers, true);
-
- const closeShortcutModalConfig = CONST.KEYBOARD_SHORTCUTS.ESCAPE;
- this.unsubscribeEscapeModal = KeyboardShortcut.subscribe(closeShortcutModalConfig.shortcutKey, () => {
- ModalActions.close();
- KeyboardShortcutsActions.hideKeyboardShortcutModal();
- }, closeShortcutModalConfig.descriptionKey, closeShortcutModalConfig.modifiers, true, true);
+ }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true);
}
componentWillUnmount() {
- if (this.unsubscribeShortcutModal) {
- this.unsubscribeShortcutModal();
- }
- if (this.unsubscribeEscapeModal) {
- this.unsubscribeEscapeModal();
+ if (!this.unsubscribeShortcutModal) {
+ return;
}
+ this.unsubscribeShortcutModal();
}
/**
@@ -93,7 +85,7 @@ class KeyboardShortcutsModal extends React.Component {
onClose={KeyboardShortcutsActions.hideKeyboardShortcutModal}
>
-
+
{this.props.translate('keyboardShortcutModal.subtitle')}
@@ -103,7 +95,7 @@ class KeyboardShortcutsModal extends React.Component {
})}
-
+
);
}
diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js
index 28cb56ecbfa2..e47e101c3ea7 100644
--- a/src/components/ScreenWrapper/index.js
+++ b/src/components/ScreenWrapper/index.js
@@ -36,7 +36,7 @@ class ScreenWrapper extends React.Component {
}
Navigation.dismissModal();
- }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true);
+ }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true);
this.unsubscribeTransitionEnd = this.props.navigation.addListener('transitionEnd', (event) => {
// Prevent firing the prop callback when user is exiting the page.
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js
deleted file mode 100644
index 338ce921221e..000000000000
--- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import _ from 'underscore';
-import getKeyEventModifiers from '../getKeyEventModifiers';
-
-/**
- * Checks if an event for that key is configured and if so, runs it.
- * @param {Function} getDisplayName
- * @param {Object} eventHandlers
- * @param {Object} keycommandEvent
- * @param {Event} event
- * @private
- */
-function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) {
- if (!(event instanceof KeyboardEvent)) {
- return;
- }
-
- const eventModifiers = getKeyEventModifiers(keycommandEvent);
- const displayName = getDisplayName(keycommandEvent.input, eventModifiers);
-
- // Loop over all the callbacks
- _.every(eventHandlers[displayName], (callback) => {
- // Early return for excludedNodes
- if (_.contains(callback.excludedNodes, event.target.nodeName)) {
- return true;
- }
-
- // If configured to do so, prevent input text control to trigger this event
- if (!callback.captureOnInputs && (
- event.target.nodeName === 'INPUT'
- || event.target.nodeName === 'TEXTAREA'
- || event.target.contentEditable === 'true'
- )) {
- return true;
- }
-
- // Determine if the event should bubble before executing the callback (which may have side-effects)
- let shouldBubble = callback.shouldBubble || false;
- if (_.isFunction(callback.shouldBubble)) {
- shouldBubble = callback.shouldBubble();
- }
-
- if (_.isFunction(callback.callback)) {
- callback.callback(event);
- }
- if (callback.shouldPreventDefault) {
- event.preventDefault();
- }
-
- // If the event should not bubble, short-circuit the loop
- return shouldBubble;
- });
-}
-
-export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js
deleted file mode 100644
index de59c819c504..000000000000
--- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import _ from 'underscore';
-import getKeyEventModifiers from '../getKeyEventModifiers';
-
-/**
- * Checks if an event for that key is configured and if so, runs it.
- * @param {Function} getDisplayName
- * @param {Object} eventHandlers
- * @param {Object} keycommandEvent
- * @param {Event} event
- * @private
- */
-function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) {
- const eventModifiers = getKeyEventModifiers(keycommandEvent);
- const displayName = getDisplayName(keycommandEvent.input, eventModifiers);
-
- // Loop over all the callbacks
- _.every(eventHandlers[displayName], (callback) => {
- // Determine if the event should bubble before executing the callback (which may have side-effects)
- let shouldBubble = callback.shouldBubble || false;
- if (_.isFunction(callback.shouldBubble)) {
- shouldBubble = callback.shouldBubble();
- }
-
- if (_.isFunction(callback.callback)) {
- callback.callback(event);
- }
-
- // If the event should not bubble, short-circuit the loop
- return shouldBubble;
- });
-}
-
-export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js
deleted file mode 100644
index 7865d51a0507..000000000000
--- a/src/libs/KeyboardShortcut/getKeyEventModifiers.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as KeyCommand from 'react-native-key-command';
-import lodashGet from 'lodash/get';
-
-/**
- * Gets modifiers from a keyboard event.
- *
- * @param {Event} event
- * @returns {Array}
- */
-function getKeyEventModifiers(event) {
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')) {
- return ['CONTROL'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')) {
- return ['META'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl')) {
- return ['CONTROL', 'Shift'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')) {
- return ['META', 'Shift'];
- }
-
- return [];
-}
-
-export default getKeyEventModifiers;
diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js
index 9ffd01bbc406..39c3a49e0609 100644
--- a/src/libs/KeyboardShortcut/index.js
+++ b/src/libs/KeyboardShortcut/index.js
@@ -1,13 +1,9 @@
import _ from 'underscore';
import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
-import * as KeyCommand from 'react-native-key-command';
-import bindHandlerToKeydownEvent from './bindHandlerToKeydownEvent';
import getOperatingSystem from '../getOperatingSystem';
import CONST from '../../CONST';
-const operatingSystem = getOperatingSystem();
-
// Handlers for the various keyboard listeners we set up
const eventHandlers = {};
@@ -21,6 +17,29 @@ function getDocumentedShortcuts() {
return _.values(documentedShortcuts);
}
+/**
+ * Gets modifiers from a keyboard event.
+ *
+ * @param {Event} event
+ * @returns {Array}
+ */
+function getKeyEventModifiers(event) {
+ const modifiers = [];
+ if (event.shiftKey) {
+ modifiers.push('SHIFT');
+ }
+ if (event.ctrlKey) {
+ modifiers.push('CONTROL');
+ }
+ if (event.altKey) {
+ modifiers.push('ALT');
+ }
+ if (event.metaKey) {
+ modifiers.push('META');
+ }
+ return modifiers;
+}
+
/**
* Generates the normalized display name for keyboard shortcuts.
*
@@ -29,23 +48,7 @@ function getDocumentedShortcuts() {
* @returns {String}
*/
function getDisplayName(key, modifiers) {
- let displayName = (() => {
- // Type of key is string and the type of KeyCommand.constants.* is number | string. Use _.isEqual to match different types.
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter').toString().toLowerCase())) {
- return ['ENTER'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape').toString().toLowerCase())) {
- return ['ESCAPE'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow').toString().toLowerCase())) {
- return ['ARROWUP'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow').toString().toLowerCase())) {
- return ['ARROWDOWN'];
- }
- return [key.toUpperCase()];
- })();
-
+ let displayName = [key.toUpperCase()];
if (_.isString(modifiers)) {
displayName.unshift(modifiers);
} else if (_.isArray(modifiers)) {
@@ -57,19 +60,56 @@ function getDisplayName(key, modifiers) {
return displayName.join(' + ');
}
-_.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => {
- const shortcutTrigger = lodashGet(shortcut, ['trigger', operatingSystem], lodashGet(shortcut, 'trigger.DEFAULT'));
-
- // If there is no trigger for the current OS nor a default trigger, then we don't need to do anything
- if (!shortcutTrigger) {
+/**
+ * Checks if an event for that key is configured and if so, runs it.
+ * @param {Event} event
+ * @private
+ */
+function bindHandlerToKeydownEvent(event) {
+ if (!(event instanceof KeyboardEvent)) {
return;
}
- KeyCommand.addListener(
- shortcutTrigger,
- (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event),
- );
-});
+ const eventModifiers = getKeyEventModifiers(event);
+ const displayName = getDisplayName(event.key, eventModifiers);
+
+ // Loop over all the callbacks
+ _.every(eventHandlers[displayName], (callback) => {
+ // Early return for excludedNodes
+ if (_.contains(callback.excludedNodes, event.target.nodeName)) {
+ return true;
+ }
+
+ // If configured to do so, prevent input text control to trigger this event
+ if (!callback.captureOnInputs && (
+ event.target.nodeName === 'INPUT'
+ || event.target.nodeName === 'TEXTAREA'
+ || event.target.contentEditable === 'true'
+ )) {
+ return true;
+ }
+
+ // Determine if the event should bubble before executing the callback (which may have side-effects)
+ let shouldBubble = callback.shouldBubble || false;
+ if (_.isFunction(callback.shouldBubble)) {
+ shouldBubble = callback.shouldBubble();
+ }
+
+ if (_.isFunction(callback.callback)) {
+ callback.callback(event);
+ }
+ if (callback.shouldPreventDefault) {
+ event.preventDefault();
+ }
+
+ // If the event should not bubble, short-circuit the loop
+ return shouldBubble;
+ });
+}
+
+// Make sure we don't add multiple listeners
+document.removeEventListener('keydown', bindHandlerToKeydownEvent, {capture: true});
+document.addEventListener('keydown', bindHandlerToKeydownEvent, {capture: true});
/**
* Unsubscribes a keyboard event handler.
@@ -89,6 +129,7 @@ function unsubscribe(displayName, callbackID) {
* @returns {Array}
*/
function getPlatformEquivalentForKeys(keys) {
+ const operatingSystem = getOperatingSystem();
return _.map(keys, (key) => {
if (!_.has(CONST.PLATFORM_SPECIFIC_KEYS, key)) {
return key;
diff --git a/src/libs/KeyboardShortcut/index.native.js b/src/libs/KeyboardShortcut/index.native.js
new file mode 100644
index 000000000000..8c97f2daf343
--- /dev/null
+++ b/src/libs/KeyboardShortcut/index.native.js
@@ -0,0 +1,12 @@
+/**
+ * This is a no-op component for native devices because they wouldn't be able to support keyboard shortcuts like
+ * a website.
+ */
+const KeyboardShortcut = {
+ subscribe() {
+ return () => {};
+ },
+ getDocumentedShortcuts() { return []; },
+};
+
+export default KeyboardShortcut;
diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js
index aca688c797c3..b2bd5bf853ab 100644
--- a/src/pages/home/report/ReportActionCompose.js
+++ b/src/pages/home/report/ReportActionCompose.js
@@ -227,7 +227,7 @@ class ReportActionCompose extends React.Component {
}
this.updateComment('', true);
- }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true);
+ }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true);
this.setMaxLines();
this.updateComment(this.comment);
diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js
index 52ae1f2e0cfc..b4a816ea5740 100644
--- a/src/pages/settings/AboutPage/AboutPage.js
+++ b/src/pages/settings/AboutPage/AboutPage.js
@@ -17,8 +17,8 @@ import Logo from '../../../../assets/images/new-expensify.svg';
import pkg from '../../../../package.json';
import * as Report from '../../../libs/actions/Report';
import * as Link from '../../../libs/actions/Link';
+import getPlatformSpecificMenuItems from './getPlatformSpecificMenuItems';
import compose from '../../../libs/compose';
-import * as KeyboardShortcuts from '../../../libs/actions/KeyboardShortcuts';
import * as ReportActionContextMenu from '../../home/report/ContextMenu/ReportActionContextMenu';
import {CONTEXT_MENU_TYPES} from '../../home/report/ContextMenu/ContextMenuActions';
@@ -30,6 +30,8 @@ const propTypes = {
const AboutPage = (props) => {
let popoverAnchor;
+ const platformSpecificMenuItems = getPlatformSpecificMenuItems(props.isSmallScreenWidth);
+
const menuItems = [
{
translationKey: 'initialSettingsPage.aboutPage.appDownloadLinks',
@@ -38,11 +40,7 @@ const AboutPage = (props) => {
Navigation.navigate(ROUTES.SETTINGS_APP_DOWNLOAD_LINKS);
},
},
- {
- translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts',
- icon: Expensicons.Keyboard,
- action: KeyboardShortcuts.showKeyboardShortcutModal,
- },
+ ...platformSpecificMenuItems,
{
translationKey: 'initialSettingsPage.aboutPage.viewTheCode',
icon: Expensicons.Eye,
diff --git a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js
new file mode 100644
index 000000000000..52f8ffa2250f
--- /dev/null
+++ b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js
@@ -0,0 +1,15 @@
+import * as KeyboardShortcuts from '../../../../libs/actions/KeyboardShortcuts';
+import * as Expensicons from '../../../../components/Icon/Expensicons';
+
+export default (isSmallScreenWidth) => {
+ if (isSmallScreenWidth) {
+ return [];
+ }
+ return [
+ {
+ translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts',
+ icon: Expensicons.Keyboard,
+ action: KeyboardShortcuts.showKeyboardShortcutModal,
+ },
+ ];
+};
diff --git a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js
new file mode 100644
index 000000000000..4ba9480748fc
--- /dev/null
+++ b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js
@@ -0,0 +1 @@
+export default () => [];
diff --git a/src/styles/styles.js b/src/styles/styles.js
index f541efeeb79d..1219ca71569f 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -2799,9 +2799,7 @@ const styles = {
keyboardShortcutModalContainer: {
maxHeight: '100%',
- flexShrink: 0,
- flexGrow: 0,
- flexBasis: 'auto',
+ flex: '0 0 auto',
},
keyboardShortcutTableWrapper: {