diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index 82850288ce42..5fe7dd1fe812 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -1,5 +1,6 @@
+import {useIsFocused} from '@react-navigation/native';
import PropTypes from 'prop-types';
-import React, {Component} from 'react';
+import React, {useCallback} from 'react';
import {ActivityIndicator, View} from 'react-native';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
@@ -7,10 +8,8 @@ import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import refPropTypes from '@components/refPropTypes';
import Text from '@components/Text';
import withNavigationFallback from '@components/withNavigationFallback';
-import withNavigationFocus from '@components/withNavigationFocus';
-import compose from '@libs/compose';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import HapticFeedback from '@libs/HapticFeedback';
-import KeyboardShortcut from '@libs/KeyboardShortcut';
import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
import themeColors from '@styles/themes/default';
@@ -112,9 +111,6 @@ const propTypes = {
/** Should enable the haptic feedback? */
shouldEnableHapticFeedback: PropTypes.bool,
- /** Whether Button is on active screen */
- isFocused: PropTypes.bool.isRequired,
-
/** Id to use for this button */
id: PropTypes.string,
@@ -161,94 +157,116 @@ const defaultProps = {
forwardedRef: undefined,
};
-class Button extends Component {
- constructor(props) {
- super(props);
-
- this.renderContent = this.renderContent.bind(this);
- }
-
- componentDidMount() {
- if (!this.props.pressOnEnter) {
- return;
- }
-
- const shortcutConfig = CONST.KEYBOARD_SHORTCUTS.ENTER;
-
- // 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)) {
- return;
- }
- this.props.onPress();
- },
- shortcutConfig.descriptionKey,
- shortcutConfig.modifiers,
- true,
- this.props.allowBubble,
- this.props.enterKeyEventListenerPriority,
- false,
- );
- }
-
- componentWillUnmount() {
- // Cleanup event listeners
- if (!this.unsubscribe) {
- return;
- }
- this.unsubscribe();
- }
-
- renderContent() {
- if (this.props.children) {
- return this.props.children;
+function Button({
+ allowBubble,
+ text,
+ shouldShowRightIcon,
+
+ icon,
+ iconRight,
+ iconFill,
+ iconStyles,
+ iconRightStyles,
+
+ small,
+ large,
+ medium,
+
+ isLoading,
+ isDisabled,
+
+ onPress,
+ onLongPress,
+ onPressIn,
+ onPressOut,
+ onMouseDown,
+
+ pressOnEnter,
+ enterKeyEventListenerPriority,
+
+ style,
+ innerStyles,
+ textStyles,
+
+ shouldUseDefaultHover,
+ success,
+ danger,
+ children,
+
+ shouldRemoveRightBorderRadius,
+ shouldRemoveLeftBorderRadius,
+ shouldEnableHapticFeedback,
+
+ id,
+ accessibilityLabel,
+ forwardedRef,
+}) {
+ const isFocused = useIsFocused();
+
+ const keyboardShortcutCallback = useCallback(
+ (event) => {
+ if (!validateSubmitShortcut(isFocused, isDisabled, isLoading, event)) {
+ return;
+ }
+ onPress();
+ },
+ [isDisabled, isFocused, isLoading, onPress],
+ );
+
+ useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, keyboardShortcutCallback, {
+ isActive: pressOnEnter,
+ shouldBubble: allowBubble,
+ priority: enterKeyEventListenerPriority,
+ shouldPreventDefault: false,
+ });
+
+ const renderContent = () => {
+ if (children) {
+ return children;
}
const textComponent = (
- {this.props.text}
+ {text}
);
- if (this.props.icon || this.props.shouldShowRightIcon) {
+ if (icon || shouldShowRightIcon) {
return (
- {this.props.icon && (
-
+ {icon && (
+
)}
{textComponent}
- {this.props.shouldShowRightIcon && (
-
+ {shouldShowRightIcon && (
+
)}
@@ -257,87 +275,85 @@ class Button extends Component {
}
return textComponent;
- }
-
- render() {
- return (
- {
- if (e && e.type === 'click') {
- e.currentTarget.blur();
- }
-
- if (this.props.shouldEnableHapticFeedback) {
- HapticFeedback.press();
- }
- return this.props.onPress(e);
- }}
- onLongPress={(e) => {
- if (this.props.shouldEnableHapticFeedback) {
- HapticFeedback.longPress();
- }
- this.props.onLongPress(e);
- }}
- onPressIn={this.props.onPressIn}
- onPressOut={this.props.onPressOut}
- onMouseDown={this.props.onMouseDown}
- disabled={this.props.isLoading || this.props.isDisabled}
- wrapperStyle={[
- this.props.isDisabled ? {...styles.cursorDisabled, ...styles.noSelect} : {},
- styles.buttonContainer,
- this.props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
- this.props.shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
- ...StyleUtils.parseStyleAsArray(this.props.style),
- ]}
- style={[
- styles.button,
- this.props.small ? styles.buttonSmall : undefined,
- this.props.medium ? styles.buttonMedium : undefined,
- this.props.large ? styles.buttonLarge : undefined,
- this.props.success ? styles.buttonSuccess : undefined,
- this.props.danger ? styles.buttonDanger : undefined,
- this.props.isDisabled && (this.props.success || this.props.danger) ? styles.buttonOpacityDisabled : undefined,
- this.props.isDisabled && !this.props.danger && !this.props.success ? styles.buttonDisabled : undefined,
- this.props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
- this.props.shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
- this.props.icon || this.props.shouldShowRightIcon ? styles.alignItemsStretch : undefined,
- ...this.props.innerStyles,
- ]}
- hoverStyle={[
- this.props.shouldUseDefaultHover && !this.props.isDisabled ? styles.buttonDefaultHovered : undefined,
- this.props.success && !this.props.isDisabled ? styles.buttonSuccessHovered : undefined,
- this.props.danger && !this.props.isDisabled ? styles.buttonDangerHovered : undefined,
- ]}
- id={this.props.id}
- accessibilityLabel={this.props.accessibilityLabel}
- role={CONST.ACCESSIBILITY_ROLE.BUTTON}
- hoverDimmingValue={1}
- >
- {this.renderContent()}
- {this.props.isLoading && (
-
- )}
-
- );
- }
+ };
+
+ return (
+ {
+ if (event && event.type === 'click') {
+ event.currentTarget.blur();
+ }
+
+ if (shouldEnableHapticFeedback) {
+ HapticFeedback.press();
+ }
+ return onPress(event);
+ }}
+ onLongPress={(event) => {
+ if (shouldEnableHapticFeedback) {
+ HapticFeedback.longPress();
+ }
+ onLongPress(event);
+ }}
+ onPressIn={onPressIn}
+ onPressOut={onPressOut}
+ onMouseDown={onMouseDown}
+ disabled={isLoading || isDisabled}
+ wrapperStyle={[
+ isDisabled ? {...styles.cursorDisabled, ...styles.noSelect} : {},
+ styles.buttonContainer,
+ shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
+ shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+ ...StyleUtils.parseStyleAsArray(style),
+ ]}
+ style={[
+ styles.button,
+ small ? styles.buttonSmall : undefined,
+ medium ? styles.buttonMedium : undefined,
+ large ? styles.buttonLarge : undefined,
+ success ? styles.buttonSuccess : undefined,
+ danger ? styles.buttonDanger : undefined,
+ isDisabled && (success || danger) ? styles.buttonOpacityDisabled : undefined,
+ isDisabled && !danger && !success ? styles.buttonDisabled : undefined,
+ shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
+ shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+ icon || shouldShowRightIcon ? styles.alignItemsStretch : undefined,
+ ...innerStyles,
+ ]}
+ hoverStyle={[
+ shouldUseDefaultHover && !isDisabled ? styles.buttonDefaultHovered : undefined,
+ success && !isDisabled ? styles.buttonSuccessHovered : undefined,
+ danger && !isDisabled ? styles.buttonDangerHovered : undefined,
+ ]}
+ id={id}
+ accessibilityLabel={accessibilityLabel}
+ role={CONST.ACCESSIBILITY_ROLE.BUTTON}
+ hoverDimmingValue={1}
+ >
+ {renderContent()}
+ {isLoading && (
+
+ )}
+
+ );
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
+Button.displayName = 'Button';
+
+const ButtonWithRef = React.forwardRef((props, ref) => (
+
+));
+
+ButtonWithRef.displayName = 'ButtonWithRef';
-export default compose(
- withNavigationFallback,
- withNavigationFocus,
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+export default withNavigationFallback(ButtonWithRef);