From 5aaced46c200a0302e795a1856b308f4ca15f85b Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 2 Mar 2022 05:20:13 +0530 Subject: [PATCH 01/16] Rename TextInputFocusable to Composer --- .../{TextInputFocusable => Composer}/index.android.js | 10 +++++----- .../{TextInputFocusable => Composer}/index.ios.js | 8 ++++---- .../{TextInputFocusable => Composer}/index.js | 9 +++++---- src/components/EmojiPicker/EmojiPickerMenu/index.js | 4 ++-- src/pages/home/report/ReportActionCompose.js | 4 ++-- src/pages/home/report/ReportActionItemMessageEdit.js | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) rename src/components/{TextInputFocusable => Composer}/index.android.js (91%) rename src/components/{TextInputFocusable => Composer}/index.ios.js (93%) rename src/components/{TextInputFocusable => Composer}/index.js (98%) diff --git a/src/components/TextInputFocusable/index.android.js b/src/components/Composer/index.android.js similarity index 91% rename from src/components/TextInputFocusable/index.android.js rename to src/components/Composer/index.android.js index 749a27d899d3..84c497b6b76c 100644 --- a/src/components/TextInputFocusable/index.android.js +++ b/src/components/Composer/index.android.js @@ -39,7 +39,7 @@ const defaultProps = { forwardedRef: null, }; -class TextInputFocusable extends React.Component { +class Composer extends React.Component { componentDidMount() { // This callback prop is used by the parent component using the constructor to // get a ref to the inner textInput element e.g. if we do @@ -76,11 +76,11 @@ class TextInputFocusable extends React.Component { } } -TextInputFocusable.displayName = 'TextInputFocusable'; -TextInputFocusable.propTypes = propTypes; -TextInputFocusable.defaultProps = defaultProps; +Composer.displayName = 'TextInputFocusable'; +Composer.propTypes = propTypes; +Composer.defaultProps = defaultProps; export default React.forwardRef((props, ref) => ( /* eslint-disable-next-line react/jsx-props-no-spreading */ - + )); diff --git a/src/components/TextInputFocusable/index.ios.js b/src/components/Composer/index.ios.js similarity index 93% rename from src/components/TextInputFocusable/index.ios.js rename to src/components/Composer/index.ios.js index 6955e6813bc5..73784ace874e 100644 --- a/src/components/TextInputFocusable/index.ios.js +++ b/src/components/Composer/index.ios.js @@ -49,7 +49,7 @@ const defaultProps = { }, }; -class TextInputFocusable extends React.Component { +class Composer extends React.Component { componentDidMount() { // This callback prop is used by the parent component using the constructor to // get a ref to the inner textInput element e.g. if we do @@ -88,10 +88,10 @@ class TextInputFocusable extends React.Component { } } -TextInputFocusable.propTypes = propTypes; -TextInputFocusable.defaultProps = defaultProps; +Composer.propTypes = propTypes; +Composer.defaultProps = defaultProps; export default React.forwardRef((props, ref) => ( /* eslint-disable-next-line react/jsx-props-no-spreading */ - + )); diff --git a/src/components/TextInputFocusable/index.js b/src/components/Composer/index.js similarity index 98% rename from src/components/TextInputFocusable/index.js rename to src/components/Composer/index.js index d7d4344faae2..47593d077ef1 100755 --- a/src/components/TextInputFocusable/index.js +++ b/src/components/Composer/index.js @@ -99,9 +99,10 @@ const IMAGE_EXTENSIONS = { }; /** + * Enable Markdown parsing. * On web we like to have the Text Input field always focused so the user can easily type a new chat */ -class TextInputFocusable extends React.Component { +class Composer extends React.Component { constructor(props) { super(props); @@ -366,10 +367,10 @@ class TextInputFocusable extends React.Component { } } -TextInputFocusable.propTypes = propTypes; -TextInputFocusable.defaultProps = defaultProps; +Composer.propTypes = propTypes; +Composer.defaultProps = defaultProps; export default withLocalize(React.forwardRef((props, ref) => ( /* eslint-disable-next-line react/jsx-props-no-spreading */ - + ))); diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 39e1862a4b46..d23c3193fbcd 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -12,7 +12,7 @@ import themeColors from '../../../styles/themes/default'; import emojis from '../../../../assets/emojis'; import EmojiPickerMenuItem from '../EmojiPickerMenuItem'; import Text from '../../Text'; -import TextInputFocusable from '../../TextInputFocusable'; +import Composer from '../../Composer'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../withWindowDimensions'; import withLocalize, {withLocalizePropTypes} from '../../withLocalize'; import compose from '../../../libs/compose'; @@ -434,7 +434,7 @@ class EmojiPickerMenu extends Component { > {!this.props.isSmallScreenWidth && ( - )} - - { this.textInput = el; From cd2f82cbad341edfad92909dee40c6f43c81f348 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 2 Mar 2022 18:45:29 +0530 Subject: [PATCH 02/16] Add TextInput Stories --- src/stories/TextInput.stories.js | 67 +++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 88c216148b84..55820f727ef4 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useState} from 'react'; import TextInput from '../components/TextInput'; /** @@ -57,6 +57,66 @@ Placeholder.args = { placeholder: 'My placeholder text', }; +const AutoGrow = Template.bind({}); +AutoGrow.storyName = 'Autogrow input'; +AutoGrow.args = { + label: 'Autogrow input', + name: 'AutoGrow', + placeholder: 'My placeholder text', +}; + +const Prefixed = Template.bind({}); +Prefixed.storyName = 'Prefixed input'; +Prefixed.args = { + label: 'Prefixed input', + name: 'Prefixed', + placeholder: 'My placeholder text', + prefixCharacter: '@', +}; + +const WithFixedLabel = Template.bind({}); +WithFixedLabel.storyName = 'Always active label'; +WithFixedLabel.args = { + label: 'Active label input', + name: 'activelabel', + placeholder: 'My placeholder text', + forceActiveLabel: 'true', +}; + +const MaxLength = Template.bind({}); +MaxLength.storyName = 'Input with maxLength'; +MaxLength.args = { + label: 'Label', + name: 'inputmaxlength', + placeholder: 'My placeholder text', + maxLength: 50, +}; + +const HintErrorInput = (args) => { + const [error, setError] = useState(''); + return ( + { + if (value && value.toLowerCase() === 'damn!') { + setError('Damn! there is an error.'); + return; + } + setError(''); + }} + errorText={error} + /> + ); +}; +HintErrorInput.storyName = 'Input with hint & error'; +HintErrorInput.args = { + label: 'Label', + name: 'inputhint&error', + placeholder: 'My placeholder text', + hint: 'Type "Damn!" to see the error.', +}; + export default story; export { AutoFocus, @@ -65,4 +125,9 @@ export { ErrorStory, ForceActiveLabel, Placeholder, + AutoGrow, + Prefixed, + WithFixedLabel, + MaxLength, + HintErrorInput, }; From b8be9ce7e04d7313456725b9a69ca50c421d98d2 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 2 Mar 2022 20:10:46 +0530 Subject: [PATCH 03/16] fix param type for story --- src/stories/TextInput.stories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 55820f727ef4..9c96c469fcb0 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -80,7 +80,7 @@ WithFixedLabel.args = { label: 'Active label input', name: 'activelabel', placeholder: 'My placeholder text', - forceActiveLabel: 'true', + forceActiveLabel: true, }; const MaxLength = Template.bind({}); From 3efd5e260cba51e2f5f510c8fb325e63828da49d Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 2 Mar 2022 23:19:09 +0530 Subject: [PATCH 04/16] Story for Composer --- .storybook/preview.js | 2 + src/stories/Composer.stories.js | 120 ++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/stories/Composer.stories.js diff --git a/.storybook/preview.js b/.storybook/preview.js index 835171bd408d..b1ef91e2fe0d 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -2,6 +2,7 @@ import React from 'react'; import Onyx from 'react-native-onyx'; import '../assets/css/fonts.css'; import ComposeProviders from '../src/components/ComposeProviders'; +import HTMLEngineProvider from '../src/components/HTMLEngineProvider'; import OnyxProvider from '../src/components/OnyxProvider'; import {LocaleContextProvider} from '../src/components/withLocalize'; import ONYXKEYS from '../src/ONYXKEYS'; @@ -16,6 +17,7 @@ const decorators = [ components={[ OnyxProvider, LocaleContextProvider, + HTMLEngineProvider, ]} > diff --git a/src/stories/Composer.stories.js b/src/stories/Composer.stories.js new file mode 100644 index 000000000000..486b2afa61e9 --- /dev/null +++ b/src/stories/Composer.stories.js @@ -0,0 +1,120 @@ +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; +import React, {useState} from 'react'; +import lodashGet from 'lodash/get'; +import {View, Image} from 'react-native'; +import Composer from '../components/Composer'; +import RenderHTML from '../components/RenderHTML'; +import Text from '../components/Text'; +import styles from '../styles/styles'; +import themeColors from '../styles/themes/default'; +import * as StyleUtils from '../styles/StyleUtils'; +import CONST from '../CONST'; + +/** + * We use the Component Story Format for writing stories. Follow the docs here: + * + * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format + */ +const story = { + title: 'Components/Composer', + component: Composer, +}; + +const parser = new ExpensiMark(); + +const Default = (args) => { + const [pastedFile, setPastedFile] = useState(null); + const [comment, setComment] = useState(args.defaultValue); + const renderedHTML = parser.replace(comment); + const [droppingFile, setDroppingFile] = useState(false); + const [isComposerDroppingTarget, setIsComposerDroppingTarget] = useState(false); + + return ( + + + { + setIsComposerDroppingTarget(isOriginComposer); + setDroppingFile(true); + }} + onDragLeave={() => { + setIsComposerDroppingTarget(false); + setDroppingFile(false); + }} + onDrop={(e) => { + e.preventDefault(); + + const file = lodashGet(e, ['dataTransfer', 'files', 0]); + if (!file) { + return; + } + + setPastedFile(file); + }} + onPasteFile={setPastedFile} + style={[styles.textInputCompose, styles.w100]} + /> + + + + Entered Comment (Drop Enabled) + {comment} + + + Rendered Comment + {Boolean(renderedHTML) && } + {pastedFile && ( + + + + )} + + + + ); +}; + +Default.args = { + autoFocus: true, + placeholder: 'Compose Text Here', + placeholderTextColor: themeColors.placeholderText, + defaultValue: `Composer can do the following: + + * It can contain MD e.g. *bold* _italic_ + * Supports Pasted Images via Ctrl+V + * Supports Drag N Drop for files.`, + isDisabled: false, + maxLines: 16, +}; + +export default story; +export { + Default, +}; From f9ad0981b305500ed5652f1362b691ef8b59ff55 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 03:51:12 +0530 Subject: [PATCH 05/16] Fix: autogrow Story --- src/stories/TextInput.stories.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 9c96c469fcb0..44ff249053e3 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -62,7 +62,11 @@ AutoGrow.storyName = 'Autogrow input'; AutoGrow.args = { label: 'Autogrow input', name: 'AutoGrow', - placeholder: 'My placeholder text', + placeholder: 'My placeholder', + autoGrow: true, + textInputContainerStyles: [{ + minWidth: 150, + }], }; const Prefixed = Template.bind({}); From 4955180322539ae8e4773f97eb868577a5fe82fb Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 04:00:06 +0530 Subject: [PATCH 06/16] Move value to state to trigger updates on value change --- src/components/TextInput/BaseTextInput.js | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 283bfa5a9ba2..7aeef5988ebf 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -19,8 +19,8 @@ class BaseTextInput extends Component { constructor(props) { super(props); - this.value = props.value || props.defaultValue || ''; - const activeLabel = props.forceActiveLabel || this.value.length > 0 || props.prefixCharacter; + const value = props.value || props.defaultValue || ''; + const activeLabel = props.forceActiveLabel || value.length > 0 || props.prefixCharacter; this.state = { isFocused: false, @@ -29,6 +29,7 @@ class BaseTextInput extends Component { passwordHidden: props.secureTextEntry, textInputWidth: 0, prefixWidth: 0, + value, }; this.input = null; @@ -61,12 +62,13 @@ class BaseTextInput extends Component { componentDidUpdate() { // Activate or deactivate the label when value is changed programmatically from outside // Only update when value prop is provided - if (this.props.value === undefined || this.value === this.props.value) { + if (this.props.value === undefined || this.state.value === this.props.value) { return; } - this.value = this.props.value; - this.input.setNativeProps({text: this.value}); + // eslint-disable-next-line react/no-did-update-set-state + this.setState({value: this.props.value}); + this.input.setNativeProps({text: this.props.value}); // In some cases, When the value prop is empty, it is not properly updated on the TextInput due to its uncontrolled nature, thus manually clearing the TextInput. if (this.props.value === '') { @@ -125,13 +127,13 @@ class BaseTextInput extends Component { if (this.props.onInputChange) { this.props.onInputChange(value); } - this.value = value; + this.setState({value}); Str.result(this.props.onChangeText, value); this.activateLabel(); } activateLabel() { - if (this.value.length < 0 || this.isLabelActive) { + if (this.state.value.length < 0 || this.isLabelActive) { return; } @@ -143,7 +145,7 @@ class BaseTextInput extends Component { } deactivateLabel() { - if (this.props.forceActiveLabel || this.value.length !== 0 || this.props.prefixCharacter) { + if (this.props.forceActiveLabel || this.state.value.length !== 0 || this.props.prefixCharacter) { return; } @@ -242,7 +244,7 @@ class BaseTextInput extends Component { }} // eslint-disable-next-line {...inputProps} - defaultValue={this.value} + defaultValue={this.state.value} placeholder={(this.props.prefixCharacter || this.state.isFocused || !this.props.label) ? this.props.placeholder : null} placeholderTextColor={themeColors.placeholderText} underlineColorAndroid="transparent" @@ -293,7 +295,7 @@ class BaseTextInput extends Component { )} {!_.isNull(this.props.maxLength) && ( - {this.value.length} + {this.state.value.length} / {this.props.maxLength} @@ -312,7 +314,7 @@ class BaseTextInput extends Component { style={[...this.props.inputStyle, styles.hiddenElementOutsideOfWindow]} onLayout={e => this.setState({textInputWidth: e.nativeEvent.layout.width})} > - {this.props.value || this.props.placeholder} + {this.state.value || this.props.placeholder} )} From 6c1c388f682a82345cb924d84e18c365101a20cd Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 04:01:35 +0530 Subject: [PATCH 07/16] Fix: AutoGrow Input styling --- src/components/TextInput/BaseTextInput.js | 20 +++++++++++--------- src/styles/StyleUtils.js | 1 - src/styles/utilities/sizing.js | 4 ++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 7aeef5988ebf..01124482dfde 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -190,6 +190,16 @@ class BaseTextInput extends Component { const hasLabel = Boolean(this.props.label.length); const inputHelpText = this.props.errorText || this.props.hint; const formHelpStyles = this.props.errorText ? styles.formError : styles.formHelp; + const textInputContainerStyles = _.reduce([ + styles.textInputContainer, + ...this.props.textInputContainerStyles, + this.props.autoGrow && StyleUtils.getAutoGrowTextInputStyle(this.state.textInputWidth), + !this.props.hideFocusedState && this.state.isFocused && styles.borderColorFocus, + (this.props.hasError || this.props.errorText) && styles.borderColorDanger, + ], (finalStyles, s) => ({ + ...finalStyles, + ...s, + }), {}); return ( <> @@ -201,15 +211,7 @@ class BaseTextInput extends Component { ]} > - + {hasLabel ? ( <> {/* Adding this background to the label only for multiline text input, diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index f16a391257ec..bc03ef314d7b 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -182,7 +182,6 @@ function getZoomSizingStyle(isZoomed, imgWidth, imgHeight, zoomScale, containerH */ function getAutoGrowTextInputStyle(width) { return { - minWidth: 5, width, }; } diff --git a/src/styles/utilities/sizing.js b/src/styles/utilities/sizing.js index 06309cedb0f8..52d4520a1292 100644 --- a/src/styles/utilities/sizing.js +++ b/src/styles/utilities/sizing.js @@ -16,6 +16,10 @@ export default { minHeight: '100%', }, + mnw2: { + minWidth: 8, + }, + w50: { width: '50%', }, From a7407a62a514e7c4b3629a4fd2965f719e6d5010 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 04:02:07 +0530 Subject: [PATCH 08/16] Visually Hide internal Text --- src/components/TextInput/BaseTextInput.js | 2 +- src/styles/styles.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 01124482dfde..653f3a390586 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -313,7 +313,7 @@ class BaseTextInput extends Component { */} {this.props.autoGrow && ( this.setState({textInputWidth: e.nativeEvent.layout.width})} > {this.state.value || this.props.placeholder} diff --git a/src/styles/styles.js b/src/styles/styles.js index 7826ad0f6e9f..c3a56f46b050 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -480,6 +480,10 @@ const styles = { height: 0, }, + visibilityHidden: { + ...visibility('hidden'), + }, + loadingVBAAnimation: { width: 160, height: 160, From ab066cbfc3180f44cd7971cb623e2000f9c7855a Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 04:06:02 +0530 Subject: [PATCH 09/16] Add comments --- src/components/TextInput/BaseTextInput.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 653f3a390586..4988fcaee22a 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -196,10 +196,7 @@ class BaseTextInput extends Component { this.props.autoGrow && StyleUtils.getAutoGrowTextInputStyle(this.state.textInputWidth), !this.props.hideFocusedState && this.state.isFocused && styles.borderColorFocus, (this.props.hasError || this.props.errorText) && styles.borderColorDanger, - ], (finalStyles, s) => ({ - ...finalStyles, - ...s, - }), {}); + ], (finalStyles, s) => ({...finalStyles, ...s}), {}); return ( <> @@ -211,7 +208,14 @@ class BaseTextInput extends Component { ]} > - + {hasLabel ? ( <> {/* Adding this background to the label only for multiline text input, From 564b55c3237c564c59da1a346a3b4f470240dc61 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 8 Mar 2022 04:11:06 +0530 Subject: [PATCH 10/16] Show the placeholder when forceActiveLabel is true --- src/components/TextInput/BaseTextInput.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 4988fcaee22a..9e9a6622357b 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -251,7 +251,16 @@ class BaseTextInput extends Component { // eslint-disable-next-line {...inputProps} defaultValue={this.state.value} - placeholder={(this.props.prefixCharacter || this.state.isFocused || !this.props.label) ? this.props.placeholder : null} + placeholder={ + ( + this.props.prefixCharacter + || this.state.isFocused + || !hasLabel + || (hasLabel && this.props.forceActiveLabel) + ) + ? this.props.placeholder + : null + } placeholderTextColor={themeColors.placeholderText} underlineColorAndroid="transparent" style={[ From e70019ef8a9bf3cb7df53709eba773917a7f4253 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 9 Mar 2022 21:25:16 +0530 Subject: [PATCH 11/16] refactor and rename --- src/components/Composer/index.android.js | 2 +- src/components/Composer/index.js | 6 ++---- src/languages/en.js | 2 +- src/languages/es.js | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/Composer/index.android.js b/src/components/Composer/index.android.js index 84c497b6b76c..ed23d98020f2 100644 --- a/src/components/Composer/index.android.js +++ b/src/components/Composer/index.android.js @@ -76,7 +76,7 @@ class Composer extends React.Component { } } -Composer.displayName = 'TextInputFocusable'; +Composer.displayName = 'Composer'; Composer.propTypes = propTypes; Composer.defaultProps = defaultProps; diff --git a/src/components/Composer/index.js b/src/components/Composer/index.js index 47593d077ef1..caec71317e84 100755 --- a/src/components/Composer/index.js +++ b/src/components/Composer/index.js @@ -198,7 +198,6 @@ class Composer extends React.Component { * Handles all types of drag-N-drop events on the composer * * @param {Object} e native Event - * @memberof TextInputFocusable */ dragNDropListener(e) { let isOriginComposer = false; @@ -238,7 +237,6 @@ class Composer extends React.Component { * Manually place the pasted HTML into Composer * * @param {String} html - pasted HTML - * @memberof TextInputFocusable */ handlePastedHTML(html) { const parser = new ExpensiMark(); @@ -286,14 +284,14 @@ class Composer extends React.Component { .then((x) => { const extension = IMAGE_EXTENSIONS[x.type]; if (!extension) { - throw new Error(this.props.translate('textInputFocusable.noExtentionFoundForMimeType')); + throw new Error(this.props.translate('composer.noExtentionFoundForMimeType')); } return new File([x], `pasted_image.${extension}`, {}); }) .then(this.props.onPasteFile) .catch(() => { - const errorDesc = this.props.translate('textInputFocusable.problemGettingImageYouPasted'); + const errorDesc = this.props.translate('composer.problemGettingImageYouPasted'); Growl.error(errorDesc); /* diff --git a/src/languages/en.js b/src/languages/en.js index 2e1deb369b4e..4934a3c606da 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -111,7 +111,7 @@ export default { attachmentTooLarge: 'Attachment too large', sizeExceeded: 'Attachment size is larger than 50 MB limit.', }, - textInputFocusable: { + composer: { noExtentionFoundForMimeType: 'No extension found for mime type', problemGettingImageYouPasted: 'There was a problem getting the image you pasted', }, diff --git a/src/languages/es.js b/src/languages/es.js index 93211173aa18..7fa4f64abaa1 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -111,7 +111,7 @@ export default { attachmentTooLarge: 'Archivo adjunto demasiado grande', sizeExceeded: 'El archivo adjunto supera el límite de 50 MB.', }, - textInputFocusable: { + composer: { noExtentionFoundForMimeType: 'No se encontró una extension para este tipo de contenido', problemGettingImageYouPasted: 'Ha ocurrido un problema al obtener la imagen que has pegado', }, From ec717fe519cba8b726d3b2261f187c8fd67a2602 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Thu, 10 Mar 2022 16:36:06 +0530 Subject: [PATCH 12/16] Clean up and refactor --- src/components/TextInput/BaseTextInput.js | 12 ++---------- src/components/TextInput/baseTextInputPropTypes.js | 1 - src/stories/Composer.stories.js | 2 +- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 9e9a6622357b..a8be3ecec95d 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -190,6 +190,7 @@ class BaseTextInput extends Component { const hasLabel = Boolean(this.props.label.length); const inputHelpText = this.props.errorText || this.props.hint; const formHelpStyles = this.props.errorText ? styles.formError : styles.formHelp; + const placeholder = (this.props.prefixCharacter || this.state.isFocused || !hasLabel || (hasLabel && this.props.forceActiveLabel)) ? this.props.placeholder : null; const textInputContainerStyles = _.reduce([ styles.textInputContainer, ...this.props.textInputContainerStyles, @@ -251,16 +252,7 @@ class BaseTextInput extends Component { // eslint-disable-next-line {...inputProps} defaultValue={this.state.value} - placeholder={ - ( - this.props.prefixCharacter - || this.state.isFocused - || !hasLabel - || (hasLabel && this.props.forceActiveLabel) - ) - ? this.props.placeholder - : null - } + placeholder={placeholder} placeholderTextColor={themeColors.placeholderText} underlineColorAndroid="transparent" style={[ diff --git a/src/components/TextInput/baseTextInputPropTypes.js b/src/components/TextInput/baseTextInputPropTypes.js index e6a612d73205..89ea048cd35d 100644 --- a/src/components/TextInput/baseTextInputPropTypes.js +++ b/src/components/TextInput/baseTextInputPropTypes.js @@ -57,7 +57,6 @@ const propTypes = { prefixCharacter: PropTypes.string, /** Form props */ - /** Indicates that the input is being used with the Form component */ isFormInput: PropTypes.bool, diff --git a/src/stories/Composer.stories.js b/src/stories/Composer.stories.js index 486b2afa61e9..6e3be856668c 100644 --- a/src/stories/Composer.stories.js +++ b/src/stories/Composer.stories.js @@ -25,9 +25,9 @@ const parser = new ExpensiMark(); const Default = (args) => { const [pastedFile, setPastedFile] = useState(null); const [comment, setComment] = useState(args.defaultValue); - const renderedHTML = parser.replace(comment); const [droppingFile, setDroppingFile] = useState(false); const [isComposerDroppingTarget, setIsComposerDroppingTarget] = useState(false); + const renderedHTML = parser.replace(comment); return ( From 6c2f5c76d6c7a3068c936ba34f139a54b5969b63 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Fri, 11 Mar 2022 13:35:41 +0530 Subject: [PATCH 13/16] Change error message --- src/stories/TextInput.stories.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 44ff249053e3..fa854aee9627 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -103,8 +103,8 @@ const HintErrorInput = (args) => { // eslint-disable-next-line react/jsx-props-no-spreading {...args} onChangeText={(value) => { - if (value && value.toLowerCase() === 'damn!') { - setError('Damn! there is an error.'); + if (value && value.toLowerCase() === 'oops!') { + setError('Oops! Looks like there\'s an error.'); return; } setError(''); @@ -118,7 +118,7 @@ HintErrorInput.args = { label: 'Label', name: 'inputhint&error', placeholder: 'My placeholder text', - hint: 'Type "Damn!" to see the error.', + hint: 'Type "Oops!" to see the error.', }; export default story; From 8a7d658a6f257d4de1f62a7f16b91dcef4c1d3fc Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Sat, 12 Mar 2022 02:14:27 +0530 Subject: [PATCH 14/16] clean up Stories --- src/stories/TextInput.stories.js | 49 ++++++++++++-------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index fa854aee9627..2ebed003b0f9 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -47,6 +47,7 @@ ErrorStory.args = { const ForceActiveLabel = Template.bind({}); ForceActiveLabel.args = { label: 'Forced active label', + placeholder: 'My placeholder text', forceActiveLabel: true, }; @@ -57,46 +58,34 @@ Placeholder.args = { placeholder: 'My placeholder text', }; -const AutoGrow = Template.bind({}); -AutoGrow.storyName = 'Autogrow input'; -AutoGrow.args = { +const AutoGrowInput = Template.bind({}); +AutoGrowInput.args = { label: 'Autogrow input', name: 'AutoGrow', - placeholder: 'My placeholder', + placeholder: 'My placeholder text', autoGrow: true, textInputContainerStyles: [{ minWidth: 150, }], }; -const Prefixed = Template.bind({}); -Prefixed.storyName = 'Prefixed input'; -Prefixed.args = { +const PrefixedInput = Template.bind({}); +PrefixedInput.args = { label: 'Prefixed input', name: 'Prefixed', placeholder: 'My placeholder text', prefixCharacter: '@', }; -const WithFixedLabel = Template.bind({}); -WithFixedLabel.storyName = 'Always active label'; -WithFixedLabel.args = { - label: 'Active label input', - name: 'activelabel', - placeholder: 'My placeholder text', - forceActiveLabel: true, -}; - -const MaxLength = Template.bind({}); -MaxLength.storyName = 'Input with maxLength'; -MaxLength.args = { - label: 'Label', - name: 'inputmaxlength', +const MaxLengthInput = Template.bind({}); +MaxLengthInput.args = { + label: 'MaxLength Input', + name: 'MaxLengthInput', placeholder: 'My placeholder text', maxLength: 50, }; -const HintErrorInput = (args) => { +const HintAndErrorInput = (args) => { const [error, setError] = useState(''); return ( { /> ); }; -HintErrorInput.storyName = 'Input with hint & error'; -HintErrorInput.args = { - label: 'Label', - name: 'inputhint&error', +HintAndErrorInput.args = { + label: 'Input with hint & error', + name: 'HintAndErrorInput', placeholder: 'My placeholder text', hint: 'Type "Oops!" to see the error.', }; @@ -129,9 +117,8 @@ export { ErrorStory, ForceActiveLabel, Placeholder, - AutoGrow, - Prefixed, - WithFixedLabel, - MaxLength, - HintErrorInput, + AutoGrowInput, + PrefixedInput, + MaxLengthInput, + HintAndErrorInput, }; From b066c8d27e8d3f6fad040942b84962e9c37d6534 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Sat, 12 Mar 2022 02:16:22 +0530 Subject: [PATCH 15/16] fix labels --- src/stories/TextInput.stories.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 2ebed003b0f9..18b854e25ffd 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -79,7 +79,7 @@ PrefixedInput.args = { const MaxLengthInput = Template.bind({}); MaxLengthInput.args = { - label: 'MaxLength Input', + label: 'MaxLength input', name: 'MaxLengthInput', placeholder: 'My placeholder text', maxLength: 50, @@ -103,7 +103,7 @@ const HintAndErrorInput = (args) => { ); }; HintAndErrorInput.args = { - label: 'Input with hint & error', + label: 'HintAndError input', name: 'HintAndErrorInput', placeholder: 'My placeholder text', hint: 'Type "Oops!" to see the error.', From ee1ecba61542bbbd89ac5c5e59c418b17a87c159 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Sat, 12 Mar 2022 04:16:00 +0530 Subject: [PATCH 16/16] Update stories --- src/stories/TextInput.stories.js | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js index 18b854e25ffd..7472f8bc2848 100644 --- a/src/stories/TextInput.stories.js +++ b/src/stories/TextInput.stories.js @@ -24,36 +24,36 @@ AutoFocus.args = { autoFocus: true, }; -const Default = Template.bind({}); -Default.args = { +const DefaultInput = Template.bind({}); +DefaultInput.args = { label: 'Default text input', name: 'Default', }; -const DefaultValue = Template.bind({}); -DefaultValue.args = { - label: 'Input with default value', +const DefaultValueInput = Template.bind({}); +DefaultValueInput.args = { + label: 'Default value input', name: 'DefaultValue', defaultValue: 'My default value', }; -const ErrorStory = Template.bind({}); -ErrorStory.args = { - label: 'Input with error', +const ErrorInput = Template.bind({}); +ErrorInput.args = { + label: 'Error input', name: 'InputWithError', - errorText: 'This field has an error.', + errorText: 'Oops! Looks like there\'s an error', }; const ForceActiveLabel = Template.bind({}); ForceActiveLabel.args = { - label: 'Forced active label', + label: 'Force active label', placeholder: 'My placeholder text', forceActiveLabel: true, }; -const Placeholder = Template.bind({}); -Placeholder.args = { - label: 'Input with placeholder', +const PlaceholderInput = Template.bind({}); +PlaceholderInput.args = { + label: 'Placeholder input', name: 'Placeholder', placeholder: 'My placeholder text', }; @@ -80,7 +80,7 @@ PrefixedInput.args = { const MaxLengthInput = Template.bind({}); MaxLengthInput.args = { label: 'MaxLength input', - name: 'MaxLengthInput', + name: 'MaxLength', placeholder: 'My placeholder text', maxLength: 50, }; @@ -93,7 +93,7 @@ const HintAndErrorInput = (args) => { {...args} onChangeText={(value) => { if (value && value.toLowerCase() === 'oops!') { - setError('Oops! Looks like there\'s an error.'); + setError('Oops! Looks like there\'s an error'); return; } setError(''); @@ -104,19 +104,19 @@ const HintAndErrorInput = (args) => { }; HintAndErrorInput.args = { label: 'HintAndError input', - name: 'HintAndErrorInput', + name: 'HintAndError', placeholder: 'My placeholder text', - hint: 'Type "Oops!" to see the error.', + hint: 'Type "Oops!" to see the error', }; export default story; export { AutoFocus, - Default, - DefaultValue, - ErrorStory, + DefaultInput, + DefaultValueInput, + ErrorInput, ForceActiveLabel, - Placeholder, + PlaceholderInput, AutoGrowInput, PrefixedInput, MaxLengthInput,