diff --git a/src/components/Button/index.js b/src/components/Button/index.js index f368f1b2ec59..65107cfe9392 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -1,9 +1,8 @@ import React, {Component} from 'react'; -import {Pressable, ActivityIndicator, View} from 'react-native'; +import {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'; @@ -15,6 +14,7 @@ import compose from '../../libs/compose'; import * as Expensicons from '../Icon/Expensicons'; import withNavigationFocus from '../withNavigationFocus'; import validateSubmitShortcut from './validateSubmitShortcut'; +import PressableWithFeedback from '../Pressable/PressableWithFeedback'; const propTypes = { /** The text for the button label */ @@ -106,6 +106,9 @@ const propTypes = { /** Id to use for this button */ nativeID: PropTypes.string, + + /** Accessibility label for the component */ + accessibilityLabel: PropTypes.string, }; const defaultProps = { @@ -137,6 +140,7 @@ const defaultProps = { shouldRemoveLeftBorderRadius: false, shouldEnableHapticFeedback: false, nativeID: '', + accessibilityLabel: '', }; class Button extends Component { @@ -235,7 +239,7 @@ class Button extends Component { render() { return ( - { if (e && e.type === 'click') { e.currentTarget.blur(); @@ -256,47 +260,42 @@ class Button extends Component { onPressOut={this.props.onPressOut} onMouseDown={this.props.onMouseDown} disabled={this.props.isLoading || this.props.isDisabled} - style={[ + 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.innerStyles, + ]} + hoverStyle={[ + this.props.success && !this.props.isDisabled ? styles.buttonSuccessHovered : undefined, + this.props.danger && !this.props.isDisabled ? styles.buttonDangerHovered : undefined, + ]} nativeID={this.props.nativeID} + accessibilityLabel={this.props.accessibilityLabel} + hoverDimmingValue={1} > - {({pressed, hovered}) => { - const activeAndHovered = !this.props.isDisabled && hovered; - return ( - - {this.renderContent()} - {this.props.isLoading && ( - - )} - - ); - }} - + {this.renderContent()} + {this.props.isLoading && ( + + )} + ); } } diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js index 6559ede70563..80664f2d3521 100644 --- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js +++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js @@ -63,7 +63,7 @@ const GenericPressable = forwardRef((props, ref) => { return props.disabled || shouldBeDisabledByScreenReader; }, [isScreenReaderActive, enableInScreenReaderStates, props.disabled]); - const onLongPressHandler = useCallback(() => { + const onLongPressHandler = useCallback((event) => { if (isDisabled) { return; } @@ -76,12 +76,12 @@ const GenericPressable = forwardRef((props, ref) => { if (ref && ref.current) { ref.current.blur(); } - onLongPress(); + onLongPress(event); Accessibility.moveAccessibilityFocus(nextFocusRef); }, [shouldUseHapticsOnLongPress, onLongPress, nextFocusRef, ref, isDisabled]); - const onPressHandler = useCallback(() => { + const onPressHandler = useCallback((event) => { if (isDisabled) { return; } @@ -91,20 +91,17 @@ const GenericPressable = forwardRef((props, ref) => { if (ref && ref.current) { ref.current.blur(); } - onPress(); + onPress(event); Accessibility.moveAccessibilityFocus(nextFocusRef); }, [shouldUseHapticsOnPress, onPress, nextFocusRef, ref, isDisabled]); - const onKeyPressHandler = useCallback( - (event) => { - if (event.key !== 'Enter') { - return; - } - onPressHandler(); - }, - [onPressHandler], - ); + const onKeyPressHandler = useCallback((event) => { + if (event.key !== 'Enter') { + return; + } + onPressHandler(event); + }, [onPressHandler]); useEffect(() => { if (!keyboardShortcut) { @@ -119,14 +116,14 @@ const GenericPressable = forwardRef((props, ref) => { hitSlop={shouldUseAutoHitSlop && hitSlop} onLayout={onLayout} ref={ref} - onPress={!isDisabled && onPressHandler} - onLongPress={!isDisabled && onLongPressHandler} - onKeyPress={!isDisabled && onKeyPressHandler} - onPressIn={!isDisabled && onPressIn} - onPressOut={!isDisabled && onPressOut} + onPress={!isDisabled ? onPressHandler : undefined} + onLongPress={!isDisabled ? onLongPressHandler : undefined} + onKeyPress={!isDisabled ? onKeyPressHandler : undefined} + onPressIn={!isDisabled ? onPressIn : undefined} + onPressOut={!isDisabled ? onPressOut : undefined} style={(state) => [ getCursorStyle(isDisabled, [props.accessibilityRole, props.role].includes('text')), - props.style, + StyleUtils.parseStyleFromFunction(props.style, state), isScreenReaderActive && StyleUtils.parseStyleFromFunction(props.screenReaderActiveStyle, state), state.focused && StyleUtils.parseStyleFromFunction(props.focusStyle, state), state.hovered && StyleUtils.parseStyleFromFunction(props.hoverStyle, state), diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js index 9e22777ea8f9..d113798e9c6e 100644 --- a/src/components/Pressable/PressableWithFeedback.js +++ b/src/components/Pressable/PressableWithFeedback.js @@ -1,6 +1,7 @@ -import React, {forwardRef} from 'react'; +import React, {forwardRef, useEffect, useState} from 'react'; import _ from 'underscore'; import propTypes from 'prop-types'; +import {InteractionManager} from 'react-native'; import GenericPressable from './GenericPressable'; import GenericPressablePropTypes from './GenericPressable/PropTypes'; import OpacityView from '../OpacityView'; @@ -24,21 +25,41 @@ const PressableWithFeedbackDefaultProps = { const PressableWithFeedback = forwardRef((props, ref) => { const propsWithoutStyling = _.omit(props, omittedProps); + const [disabled, setDisabled] = useState(props.disabled); + + useEffect(() => { + setDisabled(props.disabled); + }, [props.disabled]); + return ( { + setDisabled(true); + const onPress = props.onPress(e); + InteractionManager.runAfterInteractions(() => { + if (!(onPress instanceof Promise)) { + setDisabled(props.disabled); + return; + } + onPress.then(() => { + setDisabled(props.disabled); + }); + }); + }} > {(state) => ( diff --git a/src/libs/Accessibility/index.js b/src/libs/Accessibility/index.js index 98a03c44c80c..890b8668291c 100644 --- a/src/libs/Accessibility/index.js +++ b/src/libs/Accessibility/index.js @@ -8,7 +8,7 @@ const useScreenReaderStatus = () => { useEffect(() => { const subscription = AccessibilityInfo.addEventListener('screenReaderChanged', setIsScreenReaderEnabled); - return subscription.remove; + return subscription && subscription.remove; }, []); return isScreenReaderEnabled; diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index e2fc5c732e2b..27ed1c85e7a0 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -868,6 +868,7 @@ function generatePolicyID() { * @param {Boolean} [makeMeAdmin] Optional, leave the calling account as an admin on the policy * @param {String} [policyName] Optional, custom policy name we will use for created workspace * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot + * @returns {Promise} */ function createWorkspace(ownerEmail = '', makeMeAdmin = false, policyName = '', transitionFromOldDot = false) { const policyID = generatePolicyID(); @@ -1078,7 +1079,7 @@ function createWorkspace(ownerEmail = '', makeMeAdmin = false, policyName = '', }, ); - Navigation.isNavigationReady().then(() => { + return Navigation.isNavigationReady().then(() => { if (transitionFromOldDot) { Navigation.dismissModal(); // Dismiss /transition route for OldDot to NewDot transitions } diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js index e99ad2584757..cec33f66530c 100755 --- a/src/pages/workspace/WorkspacesListPage.js +++ b/src/pages/workspace/WorkspacesListPage.js @@ -197,6 +197,7 @@ class WorkspacesListPage extends Component { )}