Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix form accessibility 2/4 #12370

Merged
merged 31 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc4fed4
Fix form submit with enter press
mdneyazahmad Sep 13, 2022
94a6584
Fix submit with enter press on invite member page
mdneyazahmad Sep 13, 2022
6c8ab0b
fix: merge conflict
mdneyazahmad Sep 26, 2022
0894d1a
fix: merge conflict
mdneyazahmad Oct 10, 2022
ac07413
refactor: form components
mdneyazahmad Oct 31, 2022
98e0061
Merge branch 'main' into fix/7916-accessibility
mdneyazahmad Oct 31, 2022
df17655
style: fix eslint error
mdneyazahmad Oct 31, 2022
b6dfd9e
Merge branch 'main' into fix/7916-accessibility
mdneyazahmad Oct 31, 2022
c0d70f6
feat: add form submit on enter key press
mdneyazahmad Oct 31, 2022
2d9e717
Merge branch 'main' into fix/7916-accessibility
mdneyazahmad Nov 2, 2022
0785afe
fix: temporarily disable press on enter
mdneyazahmad Nov 7, 2022
81ec3f0
refactor: rename variable names
mdneyazahmad Nov 7, 2022
a944918
fix: merge conflict
mdneyazahmad Nov 21, 2022
3272d34
fix: add missing prop
mdneyazahmad Nov 21, 2022
d5bf3b1
refactor: form submit component
mdneyazahmad Nov 21, 2022
8a3286b
docs: update comments
mdneyazahmad Nov 21, 2022
796bd14
feat: add submit on enter press for multiline text input
mdneyazahmad Nov 22, 2022
acaf7c5
docs: update comments
mdneyazahmad Nov 22, 2022
b6fe28e
docs: update comments
mdneyazahmad Nov 22, 2022
7d33938
docs: update comment
mdneyazahmad Nov 23, 2022
901fd3a
Merge branch 'main' into fix/7916-accessibility
mdneyazahmad Nov 28, 2022
4bd8ca7
fix: merge conflict
mdneyazahmad Dec 26, 2022
18f9f57
Merge branch 'main' into fix/7916-accessibility
mdneyazahmad Dec 28, 2022
ac9019d
fix(WorkspaceInvitePage): submit form with
mdneyazahmad Dec 30, 2022
d8d12c9
fix: merge conflict
mdneyazahmad Dec 30, 2022
d7b0a2d
merge main
mdneyazahmad Jan 5, 2023
6dc6c4d
style: fix lint error
mdneyazahmad Jan 5, 2023
89a5a6b
fix: merge conflict
mdneyazahmad Jan 23, 2023
8f46d97
chore: resolve merge conflicts
mdneyazahmad Jan 25, 2023
8992709
fix: add style proptype
mdneyazahmad Jan 25, 2023
e952bca
fix: style proptype error
mdneyazahmad Jan 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/components/Form.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import lodashGet from 'lodash/get';
import React from 'react';
import {View, ScrollView} from 'react-native';
import {ScrollView, StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
Expand All @@ -10,8 +10,10 @@ import * as FormActions from '../libs/actions/FormActions';
import * as ErrorUtils from '../libs/ErrorUtils';
import styles from '../styles/styles';
import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
import FormSubmit from './FormSubmit';
import SafeAreaConsumer from './SafeAreaConsumer';
import ScrollViewWithContext from './ScrollViewWithContext';
import stylePropTypes from '../styles/stylePropTypes';

const propTypes = {
/** A unique Onyx key identifying the form */
Expand Down Expand Up @@ -67,6 +69,9 @@ const propTypes = {
*/
scrollContextEnabled: PropTypes.bool,

/** Container styles */
style: stylePropTypes,

...withLocalizePropTypes,
};

Expand All @@ -81,6 +86,7 @@ const defaultProps = {
isSubmitActionDangerous: false,
scrollToOverflowEnabled: false,
scrollContextEnabled: false,
style: [],
};

class Form extends React.Component {
Expand Down Expand Up @@ -273,7 +279,7 @@ class Form extends React.Component {

render() {
const scrollViewContent = safeAreaPaddingBottomStyle => (
<View style={[this.props.style, safeAreaPaddingBottomStyle]}>
<FormSubmit style={StyleSheet.flatten([this.props.style, safeAreaPaddingBottomStyle])} onSubmit={this.submit}>
{this.childrenWrapperWithProps(this.props.children)}
{this.props.isSubmitButtonVisible && (
<FormAlertWithSubmitButton
Expand All @@ -298,9 +304,10 @@ class Form extends React.Component {
containerStyles={[styles.mh0, styles.mt5, styles.flex1]}
enabledWhenOffline={this.props.enabledWhenOffline}
isSubmitActionDangerous={this.props.isSubmitActionDangerous}
disablePressOnEnter
/>
)}
</View>
</FormSubmit>
);

return (
Expand Down
6 changes: 5 additions & 1 deletion src/components/FormAlertWithSubmitButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const propTypes = {
/** Should the button be enabled when offline */
enabledWhenOffline: PropTypes.bool,

/** Disable press on enter for submit button */
disablePressOnEnter: PropTypes.bool,

/** Whether the form submit action is dangerous */
isSubmitActionDangerous: PropTypes.bool,
};
Expand All @@ -48,6 +51,7 @@ const defaultProps = {
isLoading: false,
onFixTheErrorsLinkPressed: () => {},
enabledWhenOffline: false,
disablePressOnEnter: false,
isSubmitActionDangerous: false,
};

Expand All @@ -70,7 +74,7 @@ const FormAlertWithSubmitButton = props => (
) : (
<Button
success
pressOnEnter
pressOnEnter={!props.disablePressOnEnter}
text={props.buttonText}
onPress={props.onSubmit}
isDisabled={props.isDisabled}
Expand Down
19 changes: 19 additions & 0 deletions src/components/FormSubmit/formSubmitPropTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import PropTypes from 'prop-types';
import stylePropTypes from '../../styles/stylePropTypes';

const propTypes = {
/* A function to execute when form is submitted with ENTER */
onSubmit: PropTypes.func.isRequired,

/** Children to wrap with FormSubmit. */
children: PropTypes.node.isRequired,

/** Container styles */
style: stylePropTypes,
};

const defaultProps = {
style: [],
};

export {propTypes, defaultProps};
59 changes: 59 additions & 0 deletions src/components/FormSubmit/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import lodashGet from 'lodash/get';
import {View} from 'react-native';
import * as formSubmitPropTypes from './formSubmitPropTypes';

// This is a wrapper component to handle the ENTER key press, and submit the form.
class FormSubmit extends React.Component {
constructor(props) {
super(props);

this.submitForm = this.submitForm.bind(this);
}

/**
* Calls the submit callback when ENTER is pressed on a form element.
* @param {Object} event
*/

submitForm(event) {
// ENTER is pressed with modifier key, do not submit the form
if (event.shiftKey || event.key !== 'Enter') {
return;
}

const tagName = lodashGet(event, 'target.tagName', '');

// ENTER is pressed on INPUT or SELECT element, call the submit callback.
if (tagName === 'INPUT' || tagName === 'SELECT') {
this.props.onSubmit();
return;
}

// Pressing Enter on TEXTAREA element adds a new line. When `dataset.submitOnEnter` prop is passed, call the submit callback.
if (tagName === 'TEXTAREA' && lodashGet(event, 'target.dataset.submitOnEnter', 'false') === 'true') {
this.props.onSubmit();
return;
}

// ENTER is pressed on checkbox element, call the submit callback.
if (lodashGet(event, 'target.role') === 'checkbox') {
this.props.onSubmit();
}
}

render() {
return (

// React-native-web prevents event bubbling on TextInput for key presses
// https://github.com/necolas/react-native-web/blob/fa47f80d34ee6cde2536b2a2241e326f84b633c4/packages/react-native-web/src/exports/TextInput/index.js#L272
// Thus use capture phase.
<View onKeyDownCapture={this.submitForm} style={this.props.style}>{this.props.children}</View>
);
}
}

FormSubmit.propTypes = formSubmitPropTypes.propTypes;
FormSubmit.defaultProps = formSubmitPropTypes.defaultProps;

export default FormSubmit;
11 changes: 11 additions & 0 deletions src/components/FormSubmit/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import {View} from 'react-native';
import * as formSubmitPropTypes from './formSubmitPropTypes';

const FormSubmit = props => <View style={props.style}>{props.children}</View>;

FormSubmit.propTypes = formSubmitPropTypes.propTypes;
FormSubmit.defaultProps = formSubmitPropTypes.defaultProps;
FormSubmit.displayName = 'FormSubmit';

export default FormSubmit;
5 changes: 5 additions & 0 deletions src/components/TextInput/BaseTextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ class BaseTextInput extends Component {
keyboardType={getSecureEntryKeyboardType(this.props.keyboardType, this.props.secureTextEntry, this.state.passwordHidden)}
value={this.state.value}
selection={this.state.selection}

// FormSubmit Enter key handler does not have access to direct props.
// `dataset.submitOnEnter` is used to indicate that pressing Enter on this input should call the submit callback.
dataSet={{submitOnEnter: this.props.multiline && this.props.submitOnEnter}}

/>
{this.props.secureTextEntry && (
<Checkbox
Expand Down
4 changes: 4 additions & 0 deletions src/components/TextInput/baseTextInputPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const propTypes = {

/** Whether we should wait before focusing the TextInput, useful when using transitions */
shouldDelayFocus: PropTypes.bool,

/** Indicate whether pressing Enter on multiline input is allowed to submit the form. */
submitOnEnter: PropTypes.bool,
};

const defaultProps = {
Expand Down Expand Up @@ -101,6 +104,7 @@ const defaultProps = {
prefixCharacter: '',
onInputChange: () => {},
shouldDelayFocus: false,
submitOnEnter: false,
};

export {propTypes, defaultProps};
41 changes: 21 additions & 20 deletions src/pages/SetPasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
import compose from '../libs/compose';
import NewPasswordForm from './settings/NewPasswordForm';
import FormAlertWithSubmitButton from '../components/FormAlertWithSubmitButton';
import FormSubmit from '../components/FormSubmit';
import * as ErrorUtils from '../libs/ErrorUtils';
import OfflineIndicator from '../components/OfflineIndicator';

Expand Down Expand Up @@ -99,26 +100,26 @@ class SetPasswordPage extends Component {
shouldShowWelcomeText
welcomeText={this.props.translate('setPasswordPage.passwordFormTitle')}
>
<View style={[styles.mb4]}>
{/* The prop onSubmitEditing is required, but it needs to stay as a no-op because the form is submitted and validated from the button below */}
<NewPasswordForm
onSubmitEditing={() => {}}
password={this.state.password}
updatePassword={password => this.setState({password})}
updateIsFormValid={isValid => this.setState({isFormValid: isValid})}
/>
</View>
<View>
<FormAlertWithSubmitButton
buttonText={buttonText}
isLoading={this.props.account.isLoading}
onSubmit={this.validateAndSubmitForm}
containerStyles={[styles.mb2, styles.mh0]}
message={error}
isAlertVisible={!_.isEmpty(error)}
isDisabled={!this.state.isFormValid}
/>
</View>
<FormSubmit onSubmit={this.validateAndSubmitForm}>
<View style={[styles.mb4]}>
<NewPasswordForm
password={this.state.password}
updatePassword={password => this.setState({password})}
updateIsFormValid={isValid => this.setState({isFormValid: isValid})}
/>
</View>
<View>
<FormAlertWithSubmitButton
buttonText={buttonText}
isLoading={this.props.account.isLoading}
onSubmit={this.validateAndSubmitForm}
containerStyles={[styles.mb2, styles.mh0]}
message={error}
isAlertVisible={!_.isEmpty(error)}
isDisabled={!this.state.isFormValid}
/>
</View>
</FormSubmit>
<OfflineIndicator containerStyles={[styles.mv1]} />
</SignInPageLayout>
</SafeAreaView>
Expand Down
3 changes: 0 additions & 3 deletions src/pages/settings/NewPasswordForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ const propTypes = {
/** Callback function called with boolean value for if the password form is valid */
updateIsFormValid: PropTypes.func.isRequired,

/** Callback function for when form is submitted */
onSubmitEditing: PropTypes.func.isRequired,
...withLocalizePropTypes,
};

Expand Down Expand Up @@ -78,7 +76,6 @@ class NewPasswordForm extends React.Component {
value={this.props.password}
onChangeText={password => this.props.updatePassword(password)}
onBlur={() => this.onBlurNewPassword()}
onSubmitEditing={() => this.props.onSubmitEditing()}
/>
<Text
style={[
Expand Down
6 changes: 4 additions & 2 deletions src/pages/workspace/WorkspaceInvitePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ONYXKEYS from '../../ONYXKEYS';
import * as Policy from '../../libs/actions/Policy';
import TextInput from '../../components/TextInput';
import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
import FormSubmit from '../../components/FormSubmit';
import OptionsSelector from '../../components/OptionsSelector';
import * as OptionsListUtils from '../../libs/OptionsListUtils';
import CONST from '../../CONST';
Expand Down Expand Up @@ -301,7 +302,7 @@ class WorkspaceInvitePage extends React.Component {
shouldShow={_.isEmpty(this.props.policy)}
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)}
>
<>
<FormSubmit style={[styles.flex1]} onSubmit={this.inviteUser}>
<HeaderWithCloseButton
title={this.props.translate('workspace.invite.invitePeople')}
subtitle={policyName}
Expand Down Expand Up @@ -354,6 +355,7 @@ class WorkspaceInvitePage extends React.Component {
message={this.props.policy.alertMessage}
containerStyles={[styles.flexReset, styles.mb0, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto]}
enabledWhenOffline
disablePressOnEnter
/>
<Pressable
onPress={this.openPrivacyURL}
Expand All @@ -368,7 +370,7 @@ class WorkspaceInvitePage extends React.Component {
</View>
</Pressable>
</View>
</>
</FormSubmit>
</FullPageNotFoundView>
)}
</ScreenWrapper>
Expand Down