Chore: Migration to Hooks - FormTextInput (#4256)

* chore: migrate TextInput from class to functional

* removing the theme props

* adding tests for the FormTextInput

* minor tweak

* applying changes requested

* changing the way we import/export the FormTextInput and TextInput

* removing left comments

* minor tweak

* fix import

Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com>
This commit is contained in:
Alex Junior 2022-06-27 15:46:59 -03:00 committed by GitHub
parent 674f0285f6
commit 1e9ae6e157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 233 additions and 275 deletions

View File

@ -9,7 +9,7 @@ import { Q } from '@nozbe/watermelondb';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
import { generateTriggerId } from '../../lib/methods/actions';
import TextInput, { IThemedTextInput } from '../TextInput';
import { TextInput, IThemedTextInput } from '../TextInput';
import { userTyping as userTypingAction } from '../../actions/room';
import styles from './styles';
import database from '../../lib/database';
@ -1135,7 +1135,6 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
defaultValue=''
multiline
testID={`messagebox-input${tmid ? '-thread' : ''}`}
theme={theme}
{...isAndroidTablet}
/>
<RightButtons

View File

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots SearchBox Item 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"allowFontScaling\\":true,\\"rejectResponderTermination\\":true,\\"underlineColorAndroid\\":\\"transparent\\",\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"System\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"padding\\":14,\\"borderWidth\\":0.5,\\"borderRadius\\":2},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\",\\"value\\":\\"\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#9ca2a8\\"},[{\\"position\\":\\"absolute\\",\\"top\\":14},{\\"right\\":15}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots SearchBox Item 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"allowFontScaling\\":true,\\"rejectResponderTermination\\":true,\\"underlineColorAndroid\\":\\"transparent\\",\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"System\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"padding\\":14,\\"borderWidth\\":0.5,\\"borderRadius\\":2},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"value\\":\\"\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#2f343d\\"},[{\\"position\\":\\"absolute\\",\\"top\\":14},{\\"right\\":15}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;

View File

@ -1,9 +1,8 @@
import React, { useCallback, useState } from 'react';
import { StyleSheet, TextInputProps, View } from 'react-native';
import { useTheme } from '../../theme';
import I18n from '../../i18n';
import FormTextInput from '../TextInput/FormTextInput';
import { FormTextInput } from '../TextInput';
const styles = StyleSheet.create({
inputContainer: {
@ -13,7 +12,6 @@ const styles = StyleSheet.create({
});
const SearchBox = ({ onChangeText, onSubmitEditing, testID }: TextInputProps): JSX.Element => {
const { theme } = useTheme();
const [text, setText] = useState('');
const internalOnChangeText = useCallback(value => {
@ -34,7 +32,6 @@ const SearchBox = ({ onChangeText, onSubmitEditing, testID }: TextInputProps): J
onChangeText={internalOnChangeText}
onSubmitEditing={onSubmitEditing}
value={text}
theme={theme}
testID={testID}
onClearInput={() => internalOnChangeText('')}
iconRight={'search'}

View File

@ -5,7 +5,7 @@ import I18n from '../i18n';
import { useTheme } from '../theme';
import sharedStyles from '../views/Styles';
import { themes } from '../lib/constants';
import TextInput from './TextInput';
import { TextInput } from './TextInput';
import { isIOS, isTablet } from '../lib/methods/helpers';
import { useOrientation } from '../dimensions';
@ -39,7 +39,6 @@ const SearchHeader = ({ onSearchChangeText, testID }: ISearchHeaderProps): JSX.E
style={[styles.title, isLight && { color: themes[theme].headerTitleColor }, { fontSize: titleFontSize }]}
placeholder={I18n.t('Search')}
onChangeText={onSearchChangeText}
theme={theme}
testID={testID}
/>
</View>

View File

@ -0,0 +1,54 @@
import React from 'react';
import { render } from '@testing-library/react-native';
import { FormTextInput } from '.';
const FormTextInputID = 'form-text-input-id';
describe('FormTextInput', () => {
test('should render the component', async () => {
const { findByTestId } = render(<FormTextInput testID={FormTextInputID} />);
const component = await findByTestId('form-text-input-id');
expect(component).toBeTruthy();
});
test('should render the component with left icon', async () => {
const { findByTestId } = render(<FormTextInput testID={FormTextInputID} iconLeft='user' />);
const component = await findByTestId(`${FormTextInputID}-icon-left`);
expect(component).toBeTruthy();
});
test('should render the component with right icon', async () => {
const { findByTestId } = render(<FormTextInput testID={FormTextInputID} iconRight='user' />);
const component = await findByTestId(`${FormTextInputID}-icon-right`);
expect(component).toBeTruthy();
});
test('should render the component with password icon', async () => {
const { findByTestId } = render(<FormTextInput testID={FormTextInputID} secureTextEntry />);
const component = await findByTestId(`${FormTextInputID}-icon-password`);
expect(component).toBeTruthy();
});
test('should render the component with loading', async () => {
const { findByTestId } = render(<FormTextInput testID={FormTextInputID} loading />);
const component = await findByTestId(`${FormTextInputID}-loading`);
expect(component).toBeTruthy();
});
test('should render the component with label', async () => {
const { findByText } = render(<FormTextInput testID={FormTextInputID} label='form text input' />);
const component = await findByText('form text input');
expect(component).toBeTruthy();
});
test('should render the component with error', async () => {
const error = {
reason: 'An error occurred'
};
const { findByText } = render(<FormTextInput testID={FormTextInputID} error={error} />);
const component = await findByText(error.reason);
expect(component).toBeTruthy();
});
});

View File

@ -1,14 +1,13 @@
import { BottomSheetTextInput } from '@gorhom/bottom-sheet';
import React from 'react';
import React, { useState } from 'react';
import { StyleProp, StyleSheet, Text, TextInput as RNTextInput, TextInputProps, TextStyle, View, ViewStyle } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import { themes } from '../../lib/constants';
import { TSupportedThemes } from '../../theme';
import { useTheme } from '../../theme';
import sharedStyles from '../../views/Styles';
import ActivityIndicator from '../ActivityIndicator';
import { CustomIcon, TIconsName } from '../CustomIcon';
import TextInput from './index';
import { TextInput } from './TextInput';
const styles = StyleSheet.create({
error: {
@ -59,112 +58,41 @@ export interface IRCTextInputProps extends TextInputProps {
containerStyle?: StyleProp<ViewStyle>;
inputStyle?: StyleProp<TextStyle>;
inputRef?: React.Ref<RNTextInput>;
testID?: string;
iconLeft?: TIconsName;
iconRight?: TIconsName;
left?: JSX.Element;
theme: TSupportedThemes;
bottomSheet?: boolean;
onClearInput?: () => void;
}
interface IRCTextInputState {
showPassword: boolean;
}
export default class FormTextInput extends React.PureComponent<IRCTextInputProps, IRCTextInputState> {
static defaultProps = {
error: {},
theme: 'light'
};
state = {
showPassword: false
};
get iconLeft() {
const { testID, iconLeft, theme } = this.props;
return iconLeft ? (
<CustomIcon
name={iconLeft}
testID={testID ? `${testID}-icon-left` : undefined}
size={20}
color={themes[theme].auxiliaryText}
style={[styles.iconContainer, styles.iconLeft]}
/>
) : null;
}
get iconRight() {
const { iconRight, theme, onClearInput, value } = this.props;
if (onClearInput && value && value.length > 0) {
return (
<Touchable onPress={onClearInput} style={[styles.iconContainer, styles.iconRight]} testID='clear-text-input'>
<CustomIcon name='input-clear' size={20} color={themes[theme].auxiliaryTintColor} />
</Touchable>
);
}
return iconRight ? (
<CustomIcon
name={iconRight}
size={20}
color={themes[theme].auxiliaryText}
style={[styles.iconContainer, styles.iconRight]}
/>
) : null;
}
get iconPassword() {
const { showPassword } = this.state;
const { testID, theme } = this.props;
return (
<Touchable onPress={this.tooglePassword} style={[styles.iconContainer, styles.iconRight]}>
<CustomIcon
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
testID={testID ? `${testID}-icon-right` : undefined}
size={20}
color={themes[theme].auxiliaryText}
/>
</Touchable>
);
}
get loading() {
const { theme } = this.props;
return <ActivityIndicator style={[styles.iconContainer, styles.iconRight]} color={themes[theme].bodyText} />;
}
tooglePassword = () => {
this.setState(prevState => ({ showPassword: !prevState.showPassword }));
};
render() {
const { showPassword } = this.state;
const {
export const FormTextInput = ({
label,
left,
error,
loading,
secureTextEntry,
containerStyle,
inputStyle,
inputRef,
iconLeft,
iconRight,
inputStyle,
onClearInput,
value,
left,
testID,
placeholder,
theme,
secureTextEntry,
bottomSheet,
placeholder,
...inputProps
} = this.props;
const { dangerColor } = themes[theme];
}: IRCTextInputProps): React.ReactElement => {
const { colors } = useTheme();
const [showPassword, setShowPassword] = useState(false);
const showClearInput = onClearInput && value && value.length > 0;
const Input = bottomSheet ? BottomSheetTextInput : TextInput;
return (
<View style={[styles.inputContainer, containerStyle]}>
{label ? (
<Text style={[styles.label, { color: themes[theme].titleText }, error?.error && { color: dangerColor }]}>{label}</Text>
<Text style={[styles.label, { color: colors.titleText }, error?.error && { color: colors.dangerColor }]}>{label}</Text>
) : null}
<View style={styles.wrap}>
<Input
style={[
@ -172,18 +100,18 @@ export default class FormTextInput extends React.PureComponent<IRCTextInputProps
iconLeft && styles.inputIconLeft,
(secureTextEntry || iconRight) && styles.inputIconRight,
{
backgroundColor: themes[theme].backgroundColor,
borderColor: themes[theme].separatorColor,
color: themes[theme].titleText
backgroundColor: colors.backgroundColor,
borderColor: colors.separatorColor,
color: colors.titleText
},
error?.error && {
color: dangerColor,
borderColor: dangerColor
color: colors.dangerColor,
borderColor: colors.dangerColor
},
inputStyle
]}
// @ts-ignore
ref={inputRef} // bottomSheetRef overlap default ref
// @ts-ignore ref error
ref={inputRef}
autoCorrect={false}
autoCapitalize='none'
underlineColorAndroid='transparent'
@ -191,17 +119,57 @@ export default class FormTextInput extends React.PureComponent<IRCTextInputProps
testID={testID}
accessibilityLabel={placeholder}
placeholder={placeholder}
theme={theme}
value={value}
{...inputProps}
/>
{iconLeft ? this.iconLeft : null}
{iconRight ? this.iconRight : null}
{secureTextEntry ? this.iconPassword : null}
{loading ? this.loading : null}
{iconLeft ? (
<CustomIcon
name={iconLeft}
testID={testID ? `${testID}-icon-left` : undefined}
size={20}
color={colors.auxiliaryText}
style={[styles.iconContainer, styles.iconLeft]}
/>
) : null}
{showClearInput ? (
<Touchable onPress={onClearInput} style={[styles.iconContainer, styles.iconRight]} testID='clear-text-input'>
<CustomIcon name='input-clear' size={20} color={colors.auxiliaryTintColor} />
</Touchable>
) : null}
{iconRight && !showClearInput ? (
<CustomIcon
name={iconRight}
testID={testID ? `${testID}-icon-right` : undefined}
size={20}
color={colors.bodyText}
style={[styles.iconContainer, styles.iconRight]}
/>
) : null}
{secureTextEntry ? (
<Touchable onPress={() => setShowPassword(!showPassword)} style={[styles.iconContainer, styles.iconRight]}>
<CustomIcon
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
testID={testID ? `${testID}-icon-password` : undefined}
size={20}
color={colors.auxiliaryText}
/>
</Touchable>
) : null}
{loading ? (
<ActivityIndicator
style={[styles.iconContainer, styles.iconRight]}
color={colors.bodyText}
testID={testID ? `${testID}-loading` : undefined}
/>
) : null}
{left}
</View>
{error && error.reason ? <Text style={[styles.error, { color: dangerColor }]}>{error.reason}</Text> : null}
{error && error.reason ? <Text style={[styles.error, { color: colors.dangerColor }]}>{error.reason}</Text> : null}
</View>
);
}
}
};

View File

@ -3,7 +3,7 @@ import React from 'react';
import { storiesOf } from '@storybook/react-native';
import { View, StyleSheet } from 'react-native';
import FormTextInput from './FormTextInput';
import { FormTextInput } from '.';
const styles = StyleSheet.create({
paddingHorizontal: {
@ -18,14 +18,12 @@ const item = {
longText: 'https://open.rocket.chat/images/logo/android-chrome-512x512.png'
};
const theme = 'light';
stories.add('Short and Long Text', () => (
<>
<View style={styles.paddingHorizontal}>
<FormTextInput label='Short Text' placeholder='placeholder' value={item.name} theme={theme} />
<FormTextInput label='Short Text' placeholder='placeholder' value={item.name} />
<FormTextInput label='Long Text' placeholder='placeholder' value={item.longText} theme={theme} />
<FormTextInput label='Long Text' placeholder='placeholder' value={item.longText} />
</View>
</>
));

View File

@ -0,0 +1,29 @@
import React from 'react';
import { I18nManager, StyleProp, StyleSheet, TextInput as RNTextInput, TextStyle } from 'react-native';
import { IRCTextInputProps } from './FormTextInput';
import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
const styles = StyleSheet.create({
input: {
...(I18nManager.isRTL ? { textAlign: 'right' } : { textAlign: 'auto' })
}
});
export interface IThemedTextInput extends IRCTextInputProps {
style: StyleProp<TextStyle>;
}
export const TextInput = React.forwardRef<RNTextInput, IThemedTextInput>(({ style, ...props }, ref) => {
const { theme } = useTheme();
return (
<RNTextInput
ref={ref}
style={[{ color: themes[theme].titleText }, style, styles.input]}
placeholderTextColor={themes[theme].auxiliaryText}
keyboardAppearance={theme === 'light' ? 'light' : 'dark'}
{...props}
/>
);
});

View File

@ -0,0 +1,2 @@
export * from './TextInput';
export * from './FormTextInput';

View File

@ -1,29 +0,0 @@
import React from 'react';
import { I18nManager, StyleProp, StyleSheet, TextInput, TextStyle } from 'react-native';
import { IRCTextInputProps } from './FormTextInput';
import { themes } from '../../lib/constants';
import { TSupportedThemes } from '../../theme';
const styles = StyleSheet.create({
input: {
...(I18nManager.isRTL ? { textAlign: 'right' } : { textAlign: 'auto' })
}
});
export interface IThemedTextInput extends IRCTextInputProps {
style: StyleProp<TextStyle>;
theme: TSupportedThemes;
}
const ThemedTextInput = React.forwardRef<TextInput, IThemedTextInput>(({ style, theme, ...props }, ref) => (
<TextInput
ref={ref}
style={[{ color: themes[theme].titleText }, style, styles.input]}
placeholderTextColor={themes[theme].auxiliaryText}
keyboardAppearance={theme === 'light' ? 'light' : 'dark'}
{...props}
/>
));
export default ThemedTextInput;

View File

@ -6,7 +6,7 @@ import Modal from 'react-native-modal';
import useDeepCompareEffect from 'use-deep-compare-effect';
import { connect } from 'react-redux';
import FormTextInput from '../TextInput/FormTextInput';
import { FormTextInput } from '../TextInput';
import I18n from '../../i18n';
import EventEmitter from '../../lib/methods/helpers/events';
import { useTheme } from '../../theme';
@ -116,7 +116,6 @@ const TwoFactor = React.memo(({ isMasterDetail }: { isMasterDetail: boolean }) =
{method?.text ? <Text style={[styles.subtitle, { color }]}>{I18n.t(method.text)}</Text> : null}
<FormTextInput
value={code}
theme={theme}
inputRef={(e: any) => InteractionManager.runAfterInteractions(() => e?.getNativeRef()?.focus())}
returnKeyType='send'
autoCapitalize='none'

View File

@ -13,7 +13,7 @@ import {
import { BlockContext } from '@rocket.chat/ui-kit';
import Button from '../../Button';
import FormTextInput from '../../TextInput/FormTextInput';
import { FormTextInput } from '../../TextInput';
import { textParser } from '../utils';
import { themes } from '../../../lib/constants';
import I18n from '../../../i18n';
@ -143,7 +143,6 @@ export const MultiSelect = React.memo(
testID='multi-select-search'
onChangeText={onSearch || onSearchChange}
placeholder={I18n.t('Search')}
theme={theme}
/>
<Items items={items} selected={selected} onSelect={onSelect} theme={theme} />
</View>

View File

@ -13,7 +13,7 @@ import {
import Markdown, { MarkdownPreview } from '../markdown';
import Button from '../Button';
import FormTextInput from '../TextInput/FormTextInput';
import { FormTextInput } from '../TextInput';
import { textParser, useBlockContext } from './utils';
import { themes } from '../../lib/constants';
import sharedStyles from '../../views/Styles';
@ -188,7 +188,6 @@ class ModalParser extends UiKitParserModal<React.ReactElement> {
plainInput(element: IElement, context: BlockContext) {
const [{ loading, value, error }, action] = useBlockContext(element, context);
const { theme } = useContext(ThemeContext);
const { multiline, actionId, placeholder } = element;
return (
<FormTextInput
@ -201,7 +200,6 @@ class ModalParser extends UiKitParserModal<React.ReactElement> {
containerStyle={styles.input}
value={value}
error={{ error }}
theme={theme}
/>
);
}

View File

@ -918,7 +918,6 @@ export function getUserInfo(userId: string) {
export const toggleFavorite = (roomId: string, favorite: boolean) => sdk.post('rooms.favorite', { roomId, favorite });
export const videoConferenceJoin = (callId: string, cam: boolean) =>
sdk.post('video-conference.join', { callId, state: { cam } });
@ -936,4 +935,3 @@ export const saveUserProfileMethod = (
export const deleteOwnAccount = (password: string, confirmRelinquish = false): any =>
// RC 0.67.0
sdk.post('users.deleteOwnAccount', { password, confirmRelinquish });

View File

@ -4,7 +4,7 @@ import { FlatList, ScrollView, StyleSheet, Switch, Text, View, SwitchProps } fro
import { dequal } from 'dequal';
import * as List from '../containers/List';
import TextInput from '../containers/TextInput';
import { TextInput } from '../containers/TextInput';
import Loading from '../containers/Loading';
import { createChannelRequest } from '../actions/createChannel';
import { removeUser } from '../actions/selectedUsers';
@ -390,7 +390,6 @@ class CreateChannelView extends React.Component<ICreateChannelViewProps, ICreate
testID='create-channel-name'
autoCorrect={false}
autoCapitalize='none'
theme={theme}
underlineColorAndroid='transparent'
/>
<List.Separator />

View File

@ -11,10 +11,9 @@ import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import { withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import Navigation from '../../lib/navigation/appNavigation';
import { createDiscussionRequest, ICreateDiscussionRequestData } from '../../actions/createDiscussion';
import { showErrorAlert } from '../../lib/methods/helpers/info';
import SafeAreaView from '../../containers/SafeAreaView';
import { goRoom } from '../../lib/methods/helpers/goRoom';
import { events, logEvent } from '../../lib/methods/helpers/log';
@ -24,7 +23,7 @@ import SelectChannel from './SelectChannel';
import { ICreateChannelViewProps, IResult, IError, ICreateChannelViewState } from './interfaces';
import { IApplicationState, ISearchLocal, ISubscription } from '../../definitions';
import { E2E_ROOM_TYPES, SWITCH_TRACK_COLOR, themes } from '../../lib/constants';
import { getRoomTitle } from '../../lib/methods/helpers';
import { getRoomTitle, showErrorAlert } from '../../lib/methods/helpers';
class CreateChannelView extends React.Component<ICreateChannelViewProps, ICreateChannelViewState> {
private channel: ISubscription;
@ -174,7 +173,6 @@ class CreateChannelView extends React.Component<ICreateChannelViewProps, ICreate
containerStyle={styles.inputStyle}
defaultValue={name}
onChangeText={(text: string) => this.setState({ name: text })}
theme={theme}
/>
<SelectUsers
server={server}

View File

@ -9,7 +9,7 @@ import I18n from '../i18n';
import log, { events, logEvent } from '../lib/methods/helpers/log';
import { withTheme } from '../theme';
import SafeAreaView from '../containers/SafeAreaView';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import Button from '../containers/Button';
import { getUserSelector } from '../selectors/login';
import { PADDING_HORIZONTAL } from '../containers/List/constants';
@ -138,7 +138,6 @@ class E2EEncryptionSecurityView extends React.Component<IE2EEncryptionSecurityVi
secureTextEntry
onSubmitEditing={this.changePassword}
testID='e2e-encryption-security-view-password'
theme={theme}
onChangeText={this.onChangePasswordText}
/>
<Button

View File

@ -9,7 +9,7 @@ import Button from '../containers/Button';
import * as HeaderButton from '../containers/HeaderButton';
import SafeAreaView from '../containers/SafeAreaView';
import StatusBar from '../containers/StatusBar';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import { IBaseScreen } from '../definitions';
import I18n from '../i18n';
import KeyboardView from '../containers/KeyboardView';
@ -87,7 +87,6 @@ class E2EEnterYourPasswordView extends React.Component<TE2EEnterYourPasswordView
testID='e2e-enter-your-password-view-password'
textContentType='password'
autoCompleteType='password'
theme={theme}
/>
<Button
onPress={this.submit}

View File

@ -3,7 +3,7 @@ import { Text } from 'react-native';
import Button from '../containers/Button';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import I18n from '../i18n';
import { themes } from '../lib/constants';
import { Services } from '../lib/services';
@ -100,7 +100,6 @@ class ForgotPasswordView extends React.Component<IForgotPasswordViewProps, IForg
onSubmitEditing={this.resetPassword}
testID='forgot-password-view-email'
containerStyle={sharedStyles.inputLastChild}
theme={theme}
/>
<Button
title={I18n.t('Reset_password')}

View File

@ -8,7 +8,7 @@ import Button from '../../containers/Button';
import Markdown from '../../containers/markdown';
import SafeAreaView from '../../containers/SafeAreaView';
import StatusBar from '../../containers/StatusBar';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import { IApplicationState, IBaseScreen } from '../../definitions';
import I18n from '../../i18n';
import { ChatsStackParamList } from '../../stacks/types';
@ -92,7 +92,7 @@ const InviteUsersView = ({ route, navigation }: IInviteUsersViewProps): React.Re
showsVerticalScrollIndicator={false}>
<StatusBar />
<View style={styles.innerContainer}>
<FormTextInput label={I18n.t('Invite_Link')} theme={theme} value={invite && invite.url} editable={false} />
<FormTextInput label={I18n.t('Invite_Link')} value={invite && invite.url} editable={false} />
{renderExpiration()}
<View style={[styles.divider, { backgroundColor: colors.separatorColor }]} />
<Button title={I18n.t('Share_Link')} type='primary' onPress={share} />

View File

@ -7,7 +7,7 @@ import { BlockContext } from '@rocket.chat/ui-kit';
import { TSupportedThemes, withTheme } from '../theme';
import { themes } from '../lib/constants';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import KeyboardView from '../containers/KeyboardView';
import I18n from '../i18n';
import { LISTENER } from '../containers/Toast';
@ -191,7 +191,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
onSubmitEditing={() => {
inputs.name?.focus();
}}
theme={theme}
editable={!!editOmnichannelContactPermission}
/>
<FormTextInput
@ -204,7 +203,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
onSubmitEditing={() => {
inputs.phone?.focus();
}}
theme={theme}
editable={!!editOmnichannelContactPermission}
/>
<FormTextInput
@ -223,7 +221,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
inputs.topic?.focus();
}
}}
theme={theme}
editable={!!editOmnichannelContactPermission}
/>
{Object.entries(customFields?.visitor || {}).map(([key, value], index, array) => (
@ -240,7 +237,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
}
inputs.topic?.focus();
}}
theme={theme}
editable={!!editOmnichannelContactPermission}
/>
))}
@ -252,7 +248,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
}}
defaultValue={livechat?.topic}
onChangeText={text => onChangeText('topic', text)}
theme={theme}
editable={!!editLivechatRoomCustomFieldsPermission}
/>
@ -284,7 +279,6 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
}
submit();
}}
theme={theme}
editable={!!editLivechatRoomCustomFieldsPermission}
/>
))}

View File

@ -9,7 +9,7 @@ import Button from '../containers/Button';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
import * as HeaderButton from '../containers/HeaderButton';
import LoginServices from '../containers/LoginServices';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import { IApplicationState, IBaseScreen } from '../definitions';
import I18n from '../i18n';
import { OutsideParamList } from '../stacks/types';
@ -170,7 +170,6 @@ class LoginView extends React.Component<ILoginViewProps, ILoginViewState> {
testID='login-view-email'
textContentType='username'
autoCompleteType='username'
theme={theme}
value={user}
/>
<FormTextInput
@ -187,7 +186,6 @@ class LoginView extends React.Component<ILoginViewProps, ILoginViewState> {
testID='login-view-password'
textContentType='password'
autoCompleteType='password'
theme={theme}
/>
<Button
title={I18n.t('Login')}

View File

@ -1,11 +1,11 @@
import React, { useState } from 'react';
import { FlatList, StyleSheet, TextInputProps, View } from 'react-native';
import FormTextInput from '../../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../../containers/TextInput';
import * as List from '../../../containers/List';
import { themes } from '../../../lib/constants';
import I18n from '../../../i18n';
import { TServerHistoryModel } from '../../../definitions/IServerHistory';
import { TServerHistoryModel } from '../../../definitions';
import Item from './Item';
import { TSupportedThemes } from '../../../theme';
@ -62,7 +62,6 @@ const ServerInput = ({
clearButtonMode='while-editing'
keyboardType='url'
textContentType='URL'
theme={theme}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
/>

View File

@ -8,7 +8,7 @@ import { deleteAccount } from '../../../../actions/login';
import { useActionSheet } from '../../../../containers/ActionSheet';
import FooterButtons from '../../../../containers/ActionSheet/FooterButtons';
import { CustomIcon } from '../../../../containers/CustomIcon';
import FormTextInput from '../../../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../../../containers/TextInput/FormTextInput';
import i18n from '../../../../i18n';
import { showErrorAlert } from '../../../../lib/methods/helpers';
import { events, logEvent } from '../../../../lib/methods/helpers/log';
@ -32,7 +32,6 @@ const AlertHeader = ({ title = '', subTitle = '' }) => {
export function DeleteAccountActionSheetContent(): React.ReactElement {
const [password, setPassword] = useState('');
const { theme } = useTheme();
const { hideActionSheet, showActionSheet } = useActionSheet();
const dispatch = useDispatch();
const insets = useSafeAreaInsets();
@ -82,7 +81,6 @@ export function DeleteAccountActionSheetContent(): React.ReactElement {
placeholder={i18n.t('Password')}
onChangeText={value => setPassword(value)}
onSubmitEditing={handleDeleteAccount}
theme={theme}
testID='room-info-edit-view-name'
secureTextEntry
inputStyle={{ borderWidth: 2 }}

View File

@ -13,10 +13,10 @@ import Touch from '../../lib/methods/helpers/touch';
import KeyboardView from '../../containers/KeyboardView';
import sharedStyles from '../Styles';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers/info';
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers';
import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../lib/methods/helpers/events';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import log, { events, logEvent } from '../../lib/methods/helpers/log';
import I18n from '../../i18n';
import Button from '../../containers/Button';
@ -428,7 +428,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
renderCustomFields = () => {
const { customFields } = this.state;
const { Accounts_CustomFields, theme } = this.props;
const { Accounts_CustomFields } = this.props;
if (!Accounts_CustomFields) {
return null;
@ -457,7 +457,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
placeholder={key}
value={customFields[key]}
testID='settings-view-language'
theme={theme}
/>
</RNPickerSelect>
);
@ -485,7 +484,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}
this.avatarUrl?.focus();
}}
theme={theme}
/>
);
});
@ -558,7 +556,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
this.username?.focus();
}}
testID='profile-view-name'
theme={theme}
/>
<FormTextInput
editable={Accounts_AllowUsernameChange}
@ -574,7 +571,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
this.email?.focus();
}}
testID='profile-view-username'
theme={theme}
/>
<FormTextInput
editable={Accounts_AllowEmailChange}
@ -592,7 +588,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
this.newPassword?.focus();
}}
testID='profile-view-email'
theme={theme}
/>
<FormTextInput
editable={Accounts_AllowPasswordChange}
@ -615,7 +610,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}}
secureTextEntry
testID='profile-view-new-password'
theme={theme}
/>
{this.renderCustomFields()}
<FormTextInput
@ -632,7 +626,6 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
onChangeText={value => this.setState({ avatarUrl: value })}
onSubmitEditing={this.submit}
testID='profile-view-avatar-url'
theme={theme}
/>
{this.renderAvatarButtons()}
<Button

View File

@ -9,7 +9,7 @@ import Button from '../containers/Button';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
import * as HeaderButton from '../containers/HeaderButton';
import LoginServices from '../containers/LoginServices';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import { IApplicationState, IBaseScreen } from '../definitions';
import I18n from '../i18n';
import { getShowLoginButton } from '../selectors/login';
@ -166,7 +166,7 @@ class RegisterView extends React.Component<IProps, any> {
renderCustomFields = () => {
const { customFields } = this.state;
const { Accounts_CustomFields, theme } = this.props;
const { Accounts_CustomFields } = this.props;
if (!Accounts_CustomFields) {
return null;
}
@ -194,7 +194,6 @@ class RegisterView extends React.Component<IProps, any> {
placeholder={key}
value={customFields[key]}
testID='register-view-custom-picker'
theme={theme}
/>
</RNPickerSelect>
);
@ -223,7 +222,6 @@ class RegisterView extends React.Component<IProps, any> {
this.avatarUrl?.focus();
}}
containerStyle={styles.inputContainer}
theme={theme}
/>
);
})}
@ -252,7 +250,6 @@ class RegisterView extends React.Component<IProps, any> {
this.usernameInput?.focus();
}}
testID='register-view-name'
theme={theme}
/>
<FormTextInput
label={I18n.t('Username')}
@ -267,7 +264,6 @@ class RegisterView extends React.Component<IProps, any> {
this.emailInput?.focus();
}}
testID='register-view-username'
theme={theme}
/>
<FormTextInput
label={I18n.t('Email')}
@ -283,7 +279,6 @@ class RegisterView extends React.Component<IProps, any> {
this.passwordInput?.focus();
}}
testID='register-view-email'
theme={theme}
/>
<FormTextInput
label={I18n.t('Password')}
@ -297,7 +292,6 @@ class RegisterView extends React.Component<IProps, any> {
onChangeText={(value: string) => this.setState({ password: value })}
onSubmitEditing={this.submit}
testID='register-view-password'
theme={theme}
/>
{this.renderCustomFields()}

View File

@ -13,7 +13,7 @@ import Avatar from '../../containers/Avatar';
import Loading from '../../containers/Loading';
import SafeAreaView from '../../containers/SafeAreaView';
import StatusBar from '../../containers/StatusBar';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import { LISTENER } from '../../containers/Toast';
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
import {
@ -588,7 +588,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
this.description?.focus();
}}
error={nameError}
theme={theme}
testID='room-info-edit-view-name'
/>
<FormTextInput
@ -601,7 +600,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
onSubmitEditing={() => {
this.topic?.focus();
}}
theme={theme}
testID='room-info-edit-view-description'
/>
<FormTextInput
@ -614,7 +612,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
onSubmitEditing={() => {
this.announcement?.focus();
}}
theme={theme}
testID='room-info-edit-view-topic'
/>
<FormTextInput
@ -627,7 +624,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
onSubmitEditing={() => {
this.joinCode?.focus();
}}
theme={theme}
testID='room-info-edit-view-announcement'
/>
{/* This TextInput avoid appears the password fill when typing into Announcements TextInput */}
@ -647,7 +643,6 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
onChangeText={value => this.setState({ joinCode: value })}
onSubmitEditing={this.submit}
secureTextEntry
theme={theme}
testID='room-info-edit-view-password'
/>
<SwitchContainer

View File

@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import I18n from '../../i18n';
import Button from '../../containers/Button';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import sharedStyles from '../Styles';
import { themes } from '../../lib/constants';
import { IApplicationState } from '../../definitions';
@ -88,7 +88,6 @@ const JoinCode = React.memo(
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Insert_Join_Code')}</Text>
<FormTextInput
value={code}
theme={theme}
// TODO: find a way to type this ref
inputRef={(e: any) => InteractionManager.runAfterInteractions(() => e?.getNativeRef()?.focus())}
returnKeyType='send'

View File

@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet, Text, TextInputProps, TouchableOpacity, TouchableOpacityProps, View } from 'react-native';
import TextInput from '../../../containers/TextInput';
import { TextInput } from '../../../containers/TextInput';
import I18n from '../../../i18n';
import sharedStyles from '../../Styles';
import { themes } from '../../../lib/constants';
@ -69,10 +69,9 @@ const Header = React.memo(
<View style={styles.container}>
<TextInput
autoFocus
style={[styles.title, isLight && titleColorStyle, { fontSize: titleFontSize }]}
style={[styles.subtitle, isLight && titleColorStyle, { fontSize: titleFontSize }]}
placeholder='Search'
onChangeText={onSearchChangeText}
theme={theme}
testID='rooms-list-view-search-input'
/>
</View>

View File

@ -6,7 +6,7 @@ import { Q } from '@nozbe/watermelondb';
import { connect } from 'react-redux';
import { dequal } from 'dequal';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import ActivityIndicator from '../../containers/ActivityIndicator';
import Markdown from '../../containers/markdown';
import Message from '../../containers/message';
@ -333,7 +333,6 @@ class SearchMessagesView extends React.Component<ISearchMessagesViewProps, ISear
onChangeText={this.search}
placeholder={I18n.t('Search_Messages')}
testID='search-message-view-input'
theme={theme}
/>
<Markdown msg={I18n.t('You_can_search_using_RegExp_eg')} theme={theme} />
<View style={[styles.divider, { backgroundColor: themes[theme].separatorColor }]} />

View File

@ -1,11 +1,10 @@
import React, { useEffect, useState } from 'react';
import { OutsideParamList } from '../stacks/types';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import Button from '../containers/Button';
import { showErrorAlert, isValidEmail } from '../lib/methods/helpers';
import I18n from '../i18n';
import { useTheme } from '../theme';
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
import log, { events, logEvent } from '../lib/methods/helpers/log';
import sharedStyles from './Styles';
@ -18,7 +17,6 @@ const SendEmailConfirmationView = ({ navigation, route }: ISendEmailConfirmation
const [email, setEmail] = useState('');
const [invalidEmail, setInvalidEmail] = useState(true);
const [isFetching, setIsFetching] = useState(false);
const { theme } = useTheme();
const validate = (val: string) => {
const isInvalidEmail = !isValidEmail(val);
@ -67,7 +65,6 @@ const SendEmailConfirmationView = ({ navigation, route }: ISendEmailConfirmation
onSubmitEditing={resendConfirmationEmail}
testID='send-email-confirmation-view-email'
containerStyle={sharedStyles.inputLastChild}
theme={theme}
value={email}
/>
<Button

View File

@ -11,15 +11,14 @@ import { themes } from '../lib/constants';
import Button from '../containers/Button';
import SafeAreaView from '../containers/SafeAreaView';
import StatusBar from '../containers/StatusBar';
import FormTextInput from '../containers/TextInput/FormTextInput';
import { FormTextInput } from '../containers/TextInput';
import { IApplicationState } from '../definitions';
import { SetUsernameStackParamList } from '../definitions/navigationTypes';
import I18n from '../i18n';
import KeyboardView from '../containers/KeyboardView';
import { getUserSelector } from '../selectors/login';
import { TSupportedThemes, withTheme } from '../theme';
import { isTablet } from '../lib/methods/helpers';
import { showErrorAlert } from '../lib/methods/helpers/info';
import { isTablet, showErrorAlert } from '../lib/methods/helpers';
import scrollPersistTaps from '../lib/methods/helpers/scrollPersistTaps';
import sharedStyles from './Styles';
import { Services } from '../lib/services';
@ -128,7 +127,6 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
testID='set-username-view-input'
clearButtonMode='while-editing'
containerStyle={sharedStyles.inputLastChild}
theme={theme}
/>
<Button
title={I18n.t('Register')}

View File

@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import TextInput from '../../../containers/TextInput';
import { TextInput } from '../../../containers/TextInput';
import I18n from '../../../i18n';
import { themes } from '../../../lib/constants';
import sharedStyles from '../../Styles';
@ -34,7 +34,6 @@ const Header = React.memo(({ searching, onChangeSearchText, theme }: IShareListH
style={[styles.search, isLight && titleColorStyle]}
placeholder={I18n.t('Search')}
onChangeText={onChangeSearchText}
theme={theme}
autoFocus
/>
</View>

View File

@ -5,7 +5,7 @@ import Touchable from 'react-native-platform-touchable';
import { themes } from '../../../lib/constants';
import I18n from '../../../i18n';
import { CustomIcon } from '../../../containers/CustomIcon';
import TextInput from '../../../containers/TextInput';
import { TextInput } from '../../../containers/TextInput';
import { useTheme } from '../../../theme';
import { isIOS } from '../../../lib/methods/helpers';
import sharedStyles from '../../Styles';
@ -80,7 +80,6 @@ const SearchBox = ({ hasCancel, onCancelPress, inputRef, ...props }: ISearchBox)
returnKeyType='search'
style={styles.input}
underlineColorAndroid='transparent'
theme={theme}
{...props}
/>
</View>

View File

@ -11,23 +11,20 @@ import { themes } from '../../lib/constants';
import I18n from '../../i18n';
import Loading from '../../containers/Loading';
import * as HeaderButton from '../../containers/HeaderButton';
import { isBlocked } from '../../lib/methods/helpers/room';
import { isReadOnly } from '../../lib/methods/helpers/isReadOnly';
import { TSupportedThemes, withTheme } from '../../theme';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import MessageBox from '../../containers/MessageBox';
import SafeAreaView from '../../containers/SafeAreaView';
import { getUserSelector } from '../../selectors/login';
import StatusBar from '../../containers/StatusBar';
import database from '../../lib/database';
import { canUploadFile } from '../../lib/methods/helpers/media';
import Thumbs from './Thumbs';
import Preview from './Preview';
import Header from './Header';
import styles from './styles';
import { IApplicationState, IServer, IShareAttachment, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
import { sendFileMessage, sendMessage } from '../../lib/methods';
import { hasPermission, isAndroid } from '../../lib/methods/helpers';
import { hasPermission, isAndroid, canUploadFile, isReadOnly, isBlocked } from '../../lib/methods/helpers';
interface IShareViewState {
selected: IShareAttachment;
@ -341,7 +338,6 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
multiline
textAlignVertical='top'
autoFocus
theme={theme}
value={text}
/>
);

View File

@ -9,13 +9,12 @@ import * as List from '../../containers/List';
import Loading from '../../containers/Loading';
import SafeAreaView from '../../containers/SafeAreaView';
import StatusIcon from '../../containers/Status/Status';
import FormTextInput from '../../containers/TextInput/FormTextInput';
import { FormTextInput } from '../../containers/TextInput';
import { IApplicationState, TUserStatus } from '../../definitions';
import I18n from '../../i18n';
import { showToast } from '../../lib/methods/helpers/showToast';
import { Services } from '../../lib/services';
import { getUserSelector } from '../../selectors/login';
import { useTheme } from '../../theme';
import { showErrorAlert } from '../../lib/methods/helpers';
import log, { events, logEvent } from '../../lib/methods/helpers/log';
@ -105,8 +104,6 @@ const StatusView = (): React.ReactElement => {
const dispatch = useDispatch();
const { setOptions, goBack } = useNavigation();
const { theme } = useTheme();
useEffect(() => {
const submit = async () => {
logEvent(events.STATUS_DONE);
@ -163,7 +160,6 @@ const StatusView = (): React.ReactElement => {
ListHeaderComponent={
<>
<FormTextInput
theme={theme}
value={statusText}
containerStyle={styles.inputContainer}
onChangeText={text => setStatusText(text)}