Skip to content

Commit

Permalink
Merge pull request #7937 from parasharrajat/textinput-prefix
Browse files Browse the repository at this point in the history
Merge TextInputWithPrefix into TextInput
  • Loading branch information
puneetlath authored Mar 4, 2022
2 parents 5ceaf62 + 791758e commit d4ed740
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 175 deletions.
2 changes: 1 addition & 1 deletion src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class Form extends React.Component {
this.setTouchedInput(inputID);
this.validate(this.inputValues);
},
onChange: (value) => {
onInputChange: (value) => {
this.inputValues[inputID] = value;
if (child.props.shouldSaveDraft) {
FormActions.setDraftValues(this.props.formID, {[inputID]: value});
Expand Down
8 changes: 3 additions & 5 deletions src/components/RoomNameInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import CONST from '../CONST';
import ONYXKEYS from '../ONYXKEYS';
import styles from '../styles/styles';
import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import withFullPolicy, {fullPolicyDefaultProps, fullPolicyPropTypes} from '../pages/workspace/withFullPolicy';
import TextInputWithPrefix from './TextInputWithPrefix';
import TextInput from './TextInput';

const propTypes = {
/** Callback to execute when the text input is modified correctly */
Expand Down Expand Up @@ -103,12 +102,11 @@ class RoomNameInput extends Component {

render() {
return (
<TextInputWithPrefix
<TextInput
disabled={this.props.disabled}
label={this.props.translate('newRoomPage.roomName')}
prefixCharacter="#"
prefixCharacter={CONST.POLICY.ROOM_PREFIX}
placeholder={this.props.translate('newRoomPage.social')}
containerStyles={[styles.mb5]}
onChange={this.setModifiedRoomName}
value={this.state.roomName.substring(1)}
errorText={this.props.errorText}
Expand Down
32 changes: 26 additions & 6 deletions src/components/TextInput/BaseTextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ class BaseTextInput extends Component {
super(props);

this.value = props.value || props.defaultValue || '';
const activeLabel = props.forceActiveLabel || this.value.length > 0;
const activeLabel = props.forceActiveLabel || this.value.length > 0 || props.prefixCharacter;

this.state = {
isFocused: false,
labelTranslateY: new Animated.Value(activeLabel ? styleConst.ACTIVE_LABEL_TRANSLATE_Y : styleConst.INACTIVE_LABEL_TRANSLATE_Y),
labelScale: new Animated.Value(activeLabel ? styleConst.ACTIVE_LABEL_SCALE : styleConst.INACTIVE_LABEL_SCALE),
passwordHidden: props.secureTextEntry,
textInputWidth: 0,
prefixWidth: 0,
};

this.input = null;
Expand All @@ -38,6 +39,7 @@ class BaseTextInput extends Component {
this.setValue = this.setValue.bind(this);
this.togglePasswordVisibility = this.togglePasswordVisibility.bind(this);
this.dismissKeyboardWhenBackgrounded = this.dismissKeyboardWhenBackgrounded.bind(this);
this.storePrefixLayoutDimensions = this.storePrefixLayoutDimensions.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -120,8 +122,8 @@ class BaseTextInput extends Component {
* @memberof BaseTextInput
*/
setValue(value) {
if (this.props.onChange) {
this.props.onChange(value);
if (this.props.onInputChange) {
this.props.onInputChange(value);
}
this.value = value;
Str.result(this.props.onChangeText, value);
Expand All @@ -141,7 +143,7 @@ class BaseTextInput extends Component {
}

deactivateLabel() {
if (this.props.forceActiveLabel || this.value.length !== 0) {
if (this.props.forceActiveLabel || this.value.length !== 0 || this.props.prefixCharacter) {
return;
}

Expand Down Expand Up @@ -176,6 +178,10 @@ class BaseTextInput extends Component {
this.setState(prevState => ({passwordHidden: !prevState.passwordHidden}));
}

storePrefixLayoutDimensions(event) {
this.setState({prefixWidth: Math.abs(event.nativeEvent.layout.width)});
}

render() {
// eslint-disable-next-line react/forbid-foreign-prop-types
const inputProps = _.omit(this.props, _.keys(baseTextInputPropTypes.propTypes));
Expand Down Expand Up @@ -215,7 +221,20 @@ class BaseTextInput extends Component {
/>
</>
) : null}
<View style={[styles.textInputAndIconContainer]}>
<View style={[styles.textInputAndIconContainer]} pointerEvents="box-none">
{Boolean(this.props.prefixCharacter) && (
<Text
pointerEvents="none"
selectable={false}
style={[
styles.textInputPrefix,
!hasLabel && styles.pv0,
]}
onLayout={this.storePrefixLayoutDimensions}
>
{this.props.prefixCharacter}
</Text>
)}
<RNTextInput
ref={(ref) => {
if (typeof this.props.innerRef === 'function') { this.props.innerRef(ref); }
Expand All @@ -224,14 +243,15 @@ class BaseTextInput extends Component {
// eslint-disable-next-line
{...inputProps}
defaultValue={this.value}
placeholder={(this.state.isFocused || !this.props.label) ? this.props.placeholder : null}
placeholder={(this.props.prefixCharacter || this.state.isFocused || !this.props.label) ? this.props.placeholder : null}
placeholderTextColor={themeColors.placeholderText}
underlineColorAndroid="transparent"
style={[
styles.flex1,
styles.w100,
this.props.inputStyle,
!hasLabel && styles.pv0,
this.props.prefixCharacter && StyleUtils.getPaddingLeft(this.state.prefixWidth + styles.pl1.paddingLeft),
this.props.secureTextEntry && styles.pr2,
]}
multiline={this.props.multiline}
Expand Down
20 changes: 15 additions & 5 deletions src/components/TextInput/baseTextInputPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ const propTypes = {
/** Forward the inner ref */
innerRef: PropTypes.func,

/** Maximum characters allowed */
maxLength: PropTypes.number,

/** Hint text to display below the TextInput */
hint: PropTypes.string,

/** Prefix character */
prefixCharacter: PropTypes.string,

/** Form props */

/** Indicates that the input is being used with the Form component */
isFormInput: PropTypes.bool,

Expand All @@ -61,11 +72,8 @@ const propTypes = {
/** Saves a draft of the input value when used in a form */
shouldSaveDraft: PropTypes.bool,

/** Maximum characters allowed */
maxLength: PropTypes.number,

/** Hint text to display below the TextInput */
hint: PropTypes.string,
/** Callback to update the value on Form when input is used in the Form component. */
onInputChange: PropTypes.func,
};

const defaultProps = {
Expand Down Expand Up @@ -94,6 +102,8 @@ const defaultProps = {
shouldSaveDraft: false,
maxLength: null,
hint: '',
prefixCharacter: '',
onInputChange: () => {},
};

export {propTypes, defaultProps};
58 changes: 0 additions & 58 deletions src/components/TextInputWithPrefix/index.android.js

This file was deleted.

56 changes: 0 additions & 56 deletions src/components/TextInputWithPrefix/index.js

This file was deleted.

5 changes: 3 additions & 2 deletions src/pages/ReportSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class ReportSettingsPage extends Component {
<Text style={[styles.formLabel]} numberOfLines={1}>
{this.props.translate('newRoomPage.roomName')}
</Text>
<View style={[styles.flexRow]}>
<View style={[styles.flexRow, styles.mb1]}>
<View style={[styles.flex3]}>
<RoomNameInput
initialValue={this.state.newRoomName}
Expand All @@ -199,12 +199,13 @@ class ReportSettingsPage extends Component {
/>
</View>
<Button
large
success={!shouldDisableRename}
text={this.props.translate('common.save')}
onPress={this.validateAndRenameReport}
style={[styles.ml2, styles.flex1]}
textStyles={[styles.label]}
innerStyles={[styles.reportSettingsChangeNameButton]}
innerStyles={[styles.ph5]}
isLoading={this.props.isLoadingRenamePolicyRoom}
isDisabled={shouldDisableRename}
/>
Expand Down
1 change: 0 additions & 1 deletion src/pages/workspace/WorkspaceNewRoomPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ class WorkspaceNewRoomPage extends React.Component {
/>
<ScrollView style={styles.flex1} contentContainerStyle={styles.p5}>
<View style={styles.mb5}>
<Text style={[styles.formLabel]}>{this.props.translate('newRoomPage.roomName')}</Text>
<RoomNameInput
initialValue={this.state.roomName}
policyID={this.state.policyID}
Expand Down
35 changes: 34 additions & 1 deletion src/stories/Form.stories.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import React, {useState} from 'react';
import {View} from 'react-native';
import TextInput from '../components/TextInput';
import AddressSearch from '../components/AddressSearch';
import Form from '../components/Form';
import * as FormActions from '../libs/actions/FormActions';
import styles from '../styles/styles';
import Text from '../components/Text';

/**
* We use the Component Story Format for writing stories. Follow the docs here:
Expand Down Expand Up @@ -50,6 +51,36 @@ const Template = (args) => {
);
};

/**
* Story to exhibit the native event handlers for TextInput in the Form Component
* @param {Object} args
* @returns {JSX}
*/
const WithNativeEventHandler = (args) => {
const [log, setLog] = useState('');

// Form consumes data from Onyx, so we initialize Onyx with the necessary data here
FormActions.setIsSubmitting(args.formID, args.formState.isSubmitting);
FormActions.setServerErrorMessage(args.formID, args.formState.serverErrorMessage);
FormActions.setDraftValues(args.formID, args.draftValues);

return (
// eslint-disable-next-line react/jsx-props-no-spreading
<Form {...args}>
<TextInput
label="Routing number"
inputID="routingNumber"
onChangeText={setLog}
isFormInput
shouldSaveDraft
/>
<Text>
{`Entered routing number: ${log}`}
</Text>
</Form>
);
};

// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Default = Template.bind({});
Expand Down Expand Up @@ -90,11 +121,13 @@ Default.args = defaultArgs;
Loading.args = {...defaultArgs, formState: {isSubmitting: true}};
ServerError.args = {...defaultArgs, formState: {isSubmitting: false, serverErrorMessage: 'There was an unexpected error. Please try again later.'}};
InputError.args = {...defaultArgs, draftValues: {routingNumber: '', accountNumber: ''}};
WithNativeEventHandler.args = {...defaultArgs, draftValues: {routingNumber: '', accountNumber: ''}};

export default story;
export {
Default,
Loading,
ServerError,
InputError,
WithNativeEventHandler,
};
Loading

0 comments on commit d4ed740

Please sign in to comment.