From 2c7dc5e40ea1071abb6eadb6a410c3e50ffbdbb4 Mon Sep 17 00:00:00 2001 From: Calinteodor Date: Tue, 8 Nov 2022 17:46:46 +0200 Subject: [PATCH] feat(base/ui/native): Use new Input component (#12526) feat(base/ui/native): replaced react native TextInput component with our native Input component --- lang/main.json | 5 +- .../base/react/components/native/styles.js | 11 +- .../base/ui/components/native/IconButton.tsx | 5 + .../base/ui/components/native/Input.tsx | 109 ++++++++-- .../base/ui/components/native/inputStyles.ts | 20 +- .../chat/components/native/ChatInputBar.js | 37 ++-- .../features/chat/components/native/styles.js | 18 +- .../gifs/components/native/GifsMenu.js | 7 +- .../features/gifs/components/native/styles.js | 12 +- .../native/AddPeopleDialog.js | 82 ++++---- .../add-people-dialog/native/styles.js | 53 +---- .../lobby/components/native/LobbyScreen.js | 26 +-- .../lobby/components/native/styles.js | 14 +- .../components/native/ClearableInput.js | 195 ------------------ .../components/native/styles.js | 49 ----- .../polls/components/AbstractPollCreate.js | 5 +- .../polls/components/native/PollCreate.js | 35 +--- .../polls/components/native/styles.js | 34 +-- .../prejoin/components/native/Prejoin.tsx | 23 +-- react/features/prejoin/components/styles.js | 4 + .../LiveStream/native/StreamKeyForm.js | 19 +- .../components/LiveStream/native/styles.js | 5 - .../components/native/SalesforceLinkDialog.js | 51 ++--- .../salesforce/components/native/styles.js | 23 +-- .../security-dialog/native/SecurityDialog.js | 4 +- .../security-dialog/native/styles.js | 3 +- .../components/native/SettingsView.tsx | 69 ++----- .../settings/components/native/styles.js | 9 +- .../components/native/SpeakerStats.js | 17 +- .../components/native/SpeakerStatsSearch.js | 54 ++--- .../speaker-stats/components/native/styles.js | 30 ++- .../welcome/components/WelcomePage.native.js | 26 +-- react/features/welcome/components/styles.js | 6 + 33 files changed, 366 insertions(+), 694 deletions(-) delete mode 100644 react/features/participants-pane/components/native/ClearableInput.js diff --git a/lang/main.json b/lang/main.json index f4e6fed252..1999df2a4d 100644 --- a/lang/main.json +++ b/lang/main.json @@ -89,7 +89,7 @@ "chat": { "enter": "Enter room", "error": "Error: your message was not sent. Reason: {{error}}", - "fieldPlaceHolder": "Type your message here", + "fieldPlaceHolder": "Aa", "lobbyChatMessageTo": "Lobby chat message to {{recipient}}", "message": "Message", "messageAccessibleTitle": "{{user}} says:", @@ -266,7 +266,7 @@ "e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.", "e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.", "embedMeeting": "Embed meeting", - "enterDisplayName": "Enter your name here", + "enterDisplayName": "Enter your name", "error": "Error", "gracefulShutdown": "Our service is currently down for maintenance. Please try again later.", "grantModeratorDialog": "Are you sure you want to grant moderator rights to {{participantName}}?", @@ -1003,6 +1003,7 @@ "displayName": "Display name", "displayNamePlaceholderText": "Eg: John Doe", "email": "Email", + "emailPlaceholderText": "email@example.com", "goTo": "Go to", "header": "Settings", "help": "Help", diff --git a/react/features/base/react/components/native/styles.js b/react/features/base/react/components/native/styles.js index a896b42085..226e46e3db 100644 --- a/react/features/base/react/components/native/styles.js +++ b/react/features/base/react/components/native/styles.js @@ -73,11 +73,11 @@ const SECTION_LIST_STYLES = { listSection: { alignItems: 'center', - backgroundColor: 'rgba(255, 255, 255, 0.2)', + backgroundColor: BaseTheme.palette.ui02, flex: 1, flexDirection: 'row', - paddingVertical: 5, - paddingHorizontal: 10 + paddingVertical: BaseTheme.spacing[1], + paddingHorizontal: BaseTheme.spacing[2] }, listSectionText: { @@ -164,5 +164,10 @@ export default { iconButtonContainerSecondary: { ...iconButtonContainer, backgroundColor: BaseTheme.palette.action02 + }, + + iconButtonContainerDisabled: { + ...iconButtonContainer, + backgroundColor: BaseTheme.palette.disabled01 } }; diff --git a/react/features/base/ui/components/native/IconButton.tsx b/react/features/base/ui/components/native/IconButton.tsx index 3a0e03a6e6..ccbcb96d33 100644 --- a/react/features/base/ui/components/native/IconButton.tsx +++ b/react/features/base/ui/components/native/IconButton.tsx @@ -44,6 +44,11 @@ const IconButton: React.FC = ({ rippleColor = tapColor; } + if (disabled) { + color = BaseTheme.palette.icon03; + iconButtonContainerStyles = styles.iconButtonContainerDisabled; + rippleColor = 'transparent'; + } return ( ) => void) | undefined; + onFocus?: ((e: NativeSyntheticEvent) => void) | undefined; + onKeyPress?: ((e: NativeSyntheticEvent) => void) | undefined; + onSubmitEditing?: (value: string) => void; + returnKeyType?: ReturnKeyTypeOptions | undefined; + secureTextEntry?: boolean | undefined; + textContentType?: any; } interface ICustomStyles { @@ -30,17 +48,33 @@ interface ICustomStyles { input?: Object; } -const Input = ({ +const Input = forwardRef(({ + accessibilityLabel, + autoCapitalize, + autoFocus, + blurOnSubmit, clearable, customStyles, disabled, error, icon, + keyboardType, label, + maxLength, + minHeight, + multiline, + numberOfLines, + onBlur, onChange, + onFocus, + onKeyPress, + onSubmitEditing, placeholder, + returnKeyType, + secureTextEntry, + textContentType, value -}: IProps) => { +}: IProps, ref) => { const [ focused, setFocused ] = useState(false); const handleChange = useCallback((e: NativeSyntheticEvent) => { const { nativeEvent: { text } } = e; @@ -52,38 +86,71 @@ const Input = ({ onChange?.(''); }, []); - const blur = useCallback(() => { + const handleBlur = useCallback((e: NativeSyntheticEvent) => { setFocused(false); + onBlur?.(e); }, []); - const focus = useCallback(() => { + const handleFocus = useCallback((e: NativeSyntheticEvent) => { setFocused(true); + onFocus?.(e); + }, []); + + const handleKeyPress = useCallback((e: NativeSyntheticEvent) => { + onKeyPress?.(e); + }, []); + + const handleSubmitEditing = useCallback((e: NativeSyntheticEvent) => { + const { nativeEvent: { text } } = e; + + onSubmitEditing?.(text); }, []); return ( - {label && {label}} + {label && { label }} }> {icon && } - {clearable && !disabled && value !== '' && ( + textContentType = { textContentType } + value = { typeof value === 'number' ? `${value}` : value } /> + { clearable && !disabled && value !== '' && ( }> @@ -95,6 +162,6 @@ const Input = ({ )} ); -}; +}); export default Input; diff --git a/react/features/base/ui/components/native/inputStyles.ts b/react/features/base/ui/components/native/inputStyles.ts index 21358031fe..018f9e35d7 100644 --- a/react/features/base/ui/components/native/inputStyles.ts +++ b/react/features/base/ui/components/native/inputStyles.ts @@ -10,7 +10,7 @@ export default { ...BaseTheme.typography.bodyShortRegularLarge, lineHeight: 0, color: BaseTheme.palette.text01, - marginBottom: 8 + marginBottom: BaseTheme.spacing[2] }, fieldContainer: { @@ -20,8 +20,8 @@ export default { icon: { position: 'absolute', zIndex: 1, - top: 13, - left: 16 + top: 14, + left: 14 }, input: { @@ -32,7 +32,8 @@ export default { borderWidth: 2, color: BaseTheme.palette.text01, paddingHorizontal: BaseTheme.spacing[3], - height: 48 + height: BaseTheme.spacing[7], + lineHeight: 20 }, inputDisabled: { @@ -51,6 +52,11 @@ export default { paddingLeft: BaseTheme.spacing[6] }, + inputMultiline: { + height: BaseTheme.spacing[10], + paddingTop: BaseTheme.spacing[2] + }, + clearableInput: { paddingRight: BaseTheme.spacing[6] }, @@ -60,9 +66,9 @@ export default { borderWidth: 0, position: 'absolute', right: 0, - top: 13, - width: 40, - height: 48 + top: 14, + width: BaseTheme.spacing[6], + height: BaseTheme.spacing[7] }, clearIcon: { diff --git a/react/features/chat/components/native/ChatInputBar.js b/react/features/chat/components/native/ChatInputBar.js index 4084c28bd5..10c810be8e 100644 --- a/react/features/chat/components/native/ChatInputBar.js +++ b/react/features/chat/components/native/ChatInputBar.js @@ -1,11 +1,12 @@ -// @flow - import React, { Component } from 'react'; -import { Platform, TextInput, TouchableOpacity, View } from 'react-native'; +import { Platform } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import { translate } from '../../../base/i18n'; -import { Icon, IconSend } from '../../../base/icons'; -import BaseTheme from '../../../base/ui/components/BaseTheme.native'; +import { IconSend } from '../../../base/icons/svg'; +import IconButton from '../../../base/ui/components/native/IconButton'; +import Input from '../../../base/ui/components/native/Input'; +import { BUTTON_TYPES } from '../../../base/ui/constants.native'; import styles from './styles'; @@ -70,32 +71,30 @@ class ChatInputBar extends Component { */ render() { return ( - - - { - this.state.showSend && - - - } - + + ); } diff --git a/react/features/chat/components/native/styles.js b/react/features/chat/components/native/styles.js index 44d2999994..4c2da43d89 100644 --- a/react/features/chat/components/native/styles.js +++ b/react/features/chat/components/native/styles.js @@ -54,17 +54,14 @@ export default { inputBar: { alignItems: 'center', - borderTopColor: 'rgb(209, 219, 231)', - borderTopWidth: 1, flexDirection: 'row', - paddingBottom: '4%', - paddingHorizontal: BaseTheme.spacing[3] + justifyContent: 'space-between', + marginLeft: BaseTheme.spacing[3], + width: '100%' }, - inputField: { - color: BaseTheme.palette.text01, - flex: 1, - height: 48 + customInput: { + width: 280 }, messageBubble: { @@ -96,9 +93,8 @@ export default { flexDirection: 'row' }, - sendButtonIcon: { - color: BaseTheme.palette.icon01, - fontSize: 22 + sendButton: { + marginRight: BaseTheme.spacing[5] }, /** diff --git a/react/features/gifs/components/native/GifsMenu.js b/react/features/gifs/components/native/GifsMenu.js index a59a550f6c..255bd722ce 100644 --- a/react/features/gifs/components/native/GifsMenu.js +++ b/react/features/gifs/components/native/GifsMenu.js @@ -5,9 +5,9 @@ import { useDispatch, useSelector } from 'react-redux'; import { createGifSentEvent, sendAnalytics } from '../../../analytics'; import JitsiScreen from '../../../base/modal/components/JitsiScreen'; +import Input from '../../../base/ui/components/native/Input'; import { sendMessage } from '../../../chat/actions.any'; import { goBack } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; -import ClearableInput from '../../../participants-pane/components/native/ClearableInput'; import { formatGifUrlMessage, getGifRating, getGifUrl } from '../../functions'; import GifsMenuFooter from './GifsMenuFooter'; @@ -45,8 +45,9 @@ const GifsMenu = () => { - diff --git a/react/features/gifs/components/native/styles.js b/react/features/gifs/components/native/styles.js index 1524134030..db919c4b92 100644 --- a/react/features/gifs/components/native/styles.js +++ b/react/features/gifs/components/native/styles.js @@ -6,15 +6,9 @@ export default { flex: 1 }, - clearableInput: { - wrapper: { - marginBottom: BaseTheme.spacing[3], - marginTop: BaseTheme.spacing[3] - }, - - input: { - textAlign: 'left' - } + customContainer: { + marginHorizontal: BaseTheme.spacing[3], + marginVertical: BaseTheme.spacing[2] }, grid: { diff --git a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js index c1330cdb26..f938838069 100644 --- a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js +++ b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js @@ -1,14 +1,11 @@ -// @flow - import _ from 'lodash'; -import React from 'react'; +import React, { ReactElement } from 'react'; import { ActivityIndicator, FlatList, TouchableOpacity, View } from 'react-native'; -import { withTheme } from 'react-native-paper'; import { AlertDialog, openDialog } from '../../../../base/dialog'; import { translate } from '../../../../base/i18n'; @@ -21,14 +18,12 @@ import { IconShare } from '../../../../base/icons'; import JitsiScreen from '../../../../base/modal/components/JitsiScreen'; -import { - AvatarListItem, - type Item -} from '../../../../base/react'; +import { AvatarListItem, type Item } from '../../../../base/react'; import { connect } from '../../../../base/redux'; +import BaseTheme from '../../../../base/ui/components/BaseTheme.native'; +import Input from '../../../../base/ui/components/native/Input'; import HeaderNavigationButton from '../../../../mobile/navigation/components/HeaderNavigationButton'; -import ClearableInput from '../../../../participants-pane/components/native/ClearableInput'; import { beginShareRoom } from '../../../../share-room'; import { INVITE_TYPES } from '../../../constants'; import AbstractAddPeopleDialog, { @@ -37,10 +32,7 @@ import AbstractAddPeopleDialog, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractAddPeopleDialog'; -import styles, { - AVATAR_SIZE, - DARK_GREY -} from './styles'; +import styles, { AVATAR_SIZE } from './styles'; type Props = AbstractProps & { @@ -109,6 +101,8 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { /** * TimeoutID to delay the search for the time the user is probably typing. */ + + /* eslint-disable-next-line no-undef */ searchTimeout: TimeoutID; /** @@ -131,6 +125,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { this._onShareMeeting = this._onShareMeeting.bind(this); this._onTypeQuery = this._onTypeQuery.bind(this); this._renderShareMeetingButton = this._renderShareMeetingButton.bind(this); + this._renderIcon = this._renderIcon.bind(this); } /** @@ -189,8 +184,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { _dialOutEnabled } = this.props; const { inviteItems, selectableItems } = this.state; - const { theme } = this.props; - const { palette } = theme; let placeholderKey = 'searchPlaceholder'; @@ -204,26 +197,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { - - {this.state.searchInprogress - ? - : } - } value = { this.state.fieldValue } /> { Boolean(inviteItems.length) && { _query: (string) => Promise>; - _renderInvitedItem: Object => React$Element | null; + _renderInvitedItem: Object => ReactElement | null; /** * Renders a single item in the invited {@code FlatList}. @@ -434,7 +414,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { * @param {number} index - The index of the currently rendered item. * @returns {?React$Element} */ - _renderInvitedItem(flatListItem, index): React$Element | null { + _renderInvitedItem(flatListItem, index): ReactElement | null { const { item } = flatListItem; const renderableItem = this._getRenderableItem(flatListItem); @@ -461,7 +441,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { ); } - _renderItem: Object => React$Element | null; + _renderItem: Object => ReactElement | null; /** * Renders a single item in the search result {@code FlatList}. @@ -471,7 +451,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { * @param {number} index - The index of the currently rendered item. * @returns {?React$Element<*>} */ - _renderItem(flatListItem, index): React$Element | null { + _renderItem(flatListItem, index): ReactElement | null { const { item } = flatListItem; const { inviteItems } = this.state; let selected = false; @@ -516,7 +496,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { ); } - _renderSeparator: () => React$Element<*> | null; + _renderSeparator: () => ReactElement | null; /** * Renders the item separator. @@ -529,7 +509,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { ); } - _renderShareMeetingButton: () => React$Element; + _renderShareMeetingButton: () => ReactElement; /** * Renders a button to share the meeting info. @@ -554,6 +534,30 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { ); } + _renderIcon: () => ReactElement; + + /** + * Renders an icon. + * + * @returns {React#Element<*>} + */ + _renderIcon() { + + if (this.state.searchInprogress) { + return ( + + ); + } + + return ( + + ); + } + /** * Shows an alert telling the user that some invitees were failed to be * invited. @@ -586,4 +590,4 @@ function _mapStateToProps(state: Object) { }; } -export default translate(connect(_mapStateToProps)(withTheme(AddPeopleDialog))); +export default translate(connect(_mapStateToProps)(AddPeopleDialog)); diff --git a/react/features/invite/components/add-people-dialog/native/styles.js b/react/features/invite/components/add-people-dialog/native/styles.js index 4632d57556..d02df370b7 100644 --- a/react/features/invite/components/add-people-dialog/native/styles.js +++ b/react/features/invite/components/add-people-dialog/native/styles.js @@ -1,12 +1,9 @@ -// @flow - import { BoxModel } from '../../../../base/styles'; import BaseTheme from '../../../../base/ui/components/BaseTheme.native'; export const AVATAR_SIZE = 40; export const DARK_GREY = 'rgb(28, 32, 37)'; export const LIGHT_GREY = 'rgb(209, 219, 232)'; -export const ICON_SIZE = 15; export default { @@ -19,6 +16,11 @@ export default { backgroundColor: LIGHT_GREY }, + customContainer: { + marginHorizontal: BaseTheme.spacing[3], + marginVertical: BaseTheme.spacing[2] + }, + avatarText: { color: DARK_GREY, fontSize: 12 @@ -41,15 +43,6 @@ export default { textAlign: 'center' }, - clearIconContainer: { - alignItems: 'center', - backgroundColor: BaseTheme.palette.section01, - borderRadius: 12, - justifyContent: 'center', - height: 24, - width: 24 - }, - /** * A special padding to avoid issues on some devices (such as Android devices with custom suggestions bar). */ @@ -92,18 +85,6 @@ export default { padding: 5 }, - searchField: { - backgroundColor: BaseTheme.palette.section01, - borderBottomRightRadius: 10, - borderTopRightRadius: 10, - color: DARK_GREY, - flex: 1, - fontSize: 17, - paddingVertical: 7, - paddingLeft: 0, - textAlign: 'left' - }, - selectedIcon: { color: BaseTheme.palette.icon01, fontSize: 20, @@ -117,29 +98,9 @@ export default { marginLeft: 85 }, - searchFieldWrapper: { - backgroundColor: BaseTheme.palette.section01, - alignItems: 'stretch', - flexDirection: 'row', - height: 36, - marginHorizontal: 15, - marginVertical: 8, - borderWidth: 0, - borderRadius: 10, - overflow: 'hidden' - }, - searchIcon: { - color: DARK_GREY, - fontSize: ICON_SIZE - }, - - searchIconWrapper: { - alignItems: 'center', - backgroundColor: BaseTheme.palette.section01, - flexDirection: 'row', - justifyContent: 'center', - width: ICON_SIZE + 16 + color: BaseTheme.palette.icon01, + fontSize: 22 }, shareIcon: { diff --git a/react/features/lobby/components/native/LobbyScreen.js b/react/features/lobby/components/native/LobbyScreen.js index 66925251ef..0cffae7281 100644 --- a/react/features/lobby/components/native/LobbyScreen.js +++ b/react/features/lobby/components/native/LobbyScreen.js @@ -1,7 +1,5 @@ -// @flow - -import React from 'react'; -import { Text, TextInput, View } from 'react-native'; +import React, { ReactElement } from 'react'; +import { Text, View } from 'react-native'; import { getConferenceName } from '../../../base/conference/functions'; import { translate } from '../../../base/i18n'; @@ -9,8 +7,9 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen'; import { LoadingIndicator } from '../../../base/react'; import { connect } from '../../../base/redux'; import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui'; -import BaseTheme from '../../../base/ui/components/BaseTheme'; +import BaseTheme from '../../../base/ui/components/BaseTheme.native'; import Button from '../../../base/ui/components/native/Button'; +import Input from '../../../base/ui/components/native/Input'; import { BUTTON_TYPES } from '../../../base/ui/constants'; import { BrandingImageBackground } from '../../../dynamic-branding/components/native'; import { LargeVideo } from '../../../large-video/components'; @@ -25,6 +24,7 @@ import AbstractLobbyScreen, { import styles from './styles'; + type Props = AbstractProps & { /** @@ -99,9 +99,9 @@ class LobbyScreen extends AbstractLobbyScreen { _onSwitchToPasswordMode: () => void; - _renderContent: () => React$Element<*>; + _renderContent: () => ReactElement; - _renderToolbarButtons: () => React$Element<*>; + _renderToolbarButtons: () => ReactElement; _onNavigateToLobbyChat: () => void; @@ -152,10 +152,10 @@ class LobbyScreen extends AbstractLobbyScreen { const { displayName } = this.state; return ( - ); } @@ -179,13 +179,13 @@ class LobbyScreen extends AbstractLobbyScreen { return ( - { _passwordJoinFailed && { t('lobby.invalidPassword') } diff --git a/react/features/lobby/components/native/styles.js b/react/features/lobby/components/native/styles.js index e7433ec7bc..a502002290 100644 --- a/react/features/lobby/components/native/styles.js +++ b/react/features/lobby/components/native/styles.js @@ -124,20 +124,12 @@ export default { formWrapper: { alignSelf: 'stretch', - justifyContent: 'center' + justifyContent: 'center', + marginTop: 38 }, - field: { - alignSelf: 'stretch', - backgroundColor: BaseTheme.palette.field02, - borderColor: SECONDARY_COLOR, - borderRadius: BaseTheme.shape.borderRadius, - borderWidth: 2, - color: BaseTheme.palette.text06, - height: BaseTheme.spacing[7], - marginTop: 38, + customInput: { marginHorizontal: BaseTheme.spacing[3], - padding: BaseTheme.spacing[2], textAlign: 'center' }, diff --git a/react/features/participants-pane/components/native/ClearableInput.js b/react/features/participants-pane/components/native/ClearableInput.js deleted file mode 100644 index 4e27677501..0000000000 --- a/react/features/participants-pane/components/native/ClearableInput.js +++ /dev/null @@ -1,195 +0,0 @@ -// @flow - -import React, { useCallback, useEffect, useState } from 'react'; -import { TextInput, TouchableOpacity, View } from 'react-native'; -import { withTheme } from 'react-native-paper'; - -import { Icon, IconCloseCircle } from '../../../base/icons'; - -import styles from './styles'; - -type Props = { - - /** - * If the input should be focused on display. - */ - autoFocus?: boolean, - - /** - * Custom styles for the component. - */ - customStyles?: Object, - - /** - * Callback for the onBlur event of the field. - */ - onBlur?: Function, - - /** - * Callback for the onChange event of the field. - */ - onChange: Function, - - /** - * Callback for the onFocus event of the field. - */ - onFocus?: Function, - - /** - * Callback to be used when the user hits Enter in the field. - */ - onSubmit?: Function, - - /** - * Placeholder text for the field. - */ - placeholder: string, - - /** - * Placeholder text color. - */ - placeholderColor?: string, - - /** - * Component to be added to the beginning of the the input. - */ - prefixComponent?: React$Node, - - /** - * The type of the return key. - */ - returnKeyType?: 'done' | 'go' | 'next' | 'search' | 'send' | 'none' | 'previous' | 'default', - - /** - * Color of the caret and selection. - */ - selectionColor?: string, - - /** - * Theme used for styles. - */ - theme: Object, - - /** - * Externally provided value. - */ - value?: string -}; - -/** - * Implements a pre-styled clearable input field. - * - * @param {Props} props - The props of the component. - * @returns {ReactElement} - */ -function ClearableInput({ - autoFocus = false, - customStyles = {}, - onBlur, - onChange, - onFocus, - onSubmit, - placeholder, - placeholderColor, - prefixComponent, - returnKeyType = 'search', - selectionColor, - theme, - value -}: Props) { - const [ val, setVal ] = useState(value || ''); - const [ focused, setFocused ] = useState(false); - const inputRef = React.createRef(); - - useEffect(() => { - if (value && value !== val) { - setVal(value); - } - }, [ value ]); - - - /** - * Callback for the onBlur event of the field. - * - * @returns {void} - */ - const _onBlur = useCallback(() => { - setFocused(false); - - onBlur && onBlur(); - }, [ onBlur ]); - - /** - * Callback for the onChange event of the field. - * - * @param {Object} evt - The static event. - * @returns {void} - */ - const _onChange = useCallback(evt => { - const { nativeEvent: { text } } = evt; - - setVal(text); - onChange && onChange(text); - }, [ onChange ]); - - /** - * Callback for the onFocus event of the field. - * - * @returns {void} - */ - const _onFocus = useCallback(() => { - setFocused(true); - - onFocus && onFocus(); - }, [ onFocus ]); - - /** - * Clears the input. - * - * @returns {void} - */ - const _clearInput = useCallback(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - setVal(''); - onChange && onChange(''); - }, [ onChange ]); - - return ( - - {prefixComponent} - - {val !== '' && ( - - - - )} - - ); -} - -export default withTheme(ClearableInput); diff --git a/react/features/participants-pane/components/native/styles.js b/react/features/participants-pane/components/native/styles.js index 5a785fb2c4..2b3267b3f3 100644 --- a/react/features/participants-pane/components/native/styles.js +++ b/react/features/participants-pane/components/native/styles.js @@ -1,4 +1,3 @@ -import { MD_ITEM_HEIGHT } from '../../../base/dialog/components/native/styles'; import BaseTheme from '../../../base/ui/components/BaseTheme.native'; /** @@ -264,54 +263,6 @@ export default { backgroundColor: BaseTheme.palette.dividerColor }, - clearableInput: { - display: 'flex', - height: MD_ITEM_HEIGHT, - borderWidth: 1, - borderStyle: 'solid', - borderColor: BaseTheme.palette.ui05, - backgroundColor: BaseTheme.palette.uiBackground, - borderRadius: BaseTheme.shape.borderRadius, - marginLeft: BaseTheme.spacing[3], - marginRight: BaseTheme.spacing[3], - marginBottom: BaseTheme.spacing[4] - }, - - clearableInputFocus: { - borderWidth: 3, - borderColor: BaseTheme.palette.field01Focus - }, - - clearButton: { - backgroundColor: 'transparent', - borderWidth: 0, - position: 'absolute', - right: 0, - top: 0, - paddingTop: 12, - paddingLeft: BaseTheme.spacing[2], - width: 40, - height: MD_ITEM_HEIGHT - }, - - clearIcon: { - color: BaseTheme.palette.icon02 - }, - - clearableInputTextInput: { - backgroundColor: 'transparent', - borderWidth: 0, - height: '100%', - width: '100%', - textAlign: 'center', - color: BaseTheme.palette.text01, - paddingTop: BaseTheme.spacing[2], - paddingBottom: BaseTheme.spacing[2], - paddingLeft: BaseTheme.spacing[3], - paddingRight: BaseTheme.spacing[3], - fontSize: 16 - }, - inputContainer: { marginLeft: BaseTheme.spacing[3], marginRight: BaseTheme.spacing[3], diff --git a/react/features/polls/components/AbstractPollCreate.js b/react/features/polls/components/AbstractPollCreate.js index b80bab0992..18d7d5872f 100644 --- a/react/features/polls/components/AbstractPollCreate.js +++ b/react/features/polls/components/AbstractPollCreate.js @@ -48,10 +48,9 @@ const AbstractPollCreate = (Component: AbstractComponent) => (pro const [ answers, setAnswers ] = useState([ '', '' ]); const setAnswer = useCallback((i, answer) => { - const newAnswers = [ ...answers ]; + answers[i] = answer; - newAnswers[i] = answer; - setAnswers(newAnswers); + setAnswers([ ...answers ]); }); const addAnswer = useCallback((i: ?number) => { diff --git a/react/features/polls/components/native/PollCreate.js b/react/features/polls/components/native/PollCreate.js index 5e3dbbf4f6..1b2ffe6b25 100644 --- a/react/features/polls/components/native/PollCreate.js +++ b/react/features/polls/components/native/PollCreate.js @@ -1,11 +1,9 @@ -// @flow - import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { FlatList, Platform, Text, TextInput, View } from 'react-native'; +import { FlatList, Platform, Text, View } from 'react-native'; import { Divider, TouchableRipple } from 'react-native-paper'; -import BaseTheme from '../../../base/ui/components/BaseTheme.native'; import Button from '../../../base/ui/components/native/Button'; +import Input from '../../../base/ui/components/native/Input'; import { BUTTON_TYPES } from '../../../base/ui/constants'; import styles from '../../../settings/components/native/styles'; @@ -42,12 +40,11 @@ const PollCreate = (props: AbstractProps) => { return; } answerInputs.current[i] = input; - }, - [ answerInputs ] - ); + }, [ answerInputs ]); useEffect(() => { answerInputs.current = answerInputs.current.slice(0, answers.length); + }, [ answers ]); /* @@ -105,22 +102,16 @@ const PollCreate = (props: AbstractProps) => { ( - - { t('polls.create.pollOption', { index: index + 1 }) } - - setAnswer(index, text) } + onChange = { text => setAnswer(index, text) } onKeyPress = { ev => onAnswerKeyDown(index, ev) } placeholder = { t('polls.create.answerPlaceholder', { index: index + 1 }) } - placeholderTextColor = { BaseTheme.palette.text03 } ref = { input => registerFieldRef(index, input) } - selectionColor = { BaseTheme.palette.action01 } - style = { dialogStyles.field } value = { answers[index] } /> - { answers.length > 2 && createRemoveOptionButton(() => removeAnswer(index)) @@ -133,20 +124,16 @@ const PollCreate = (props: AbstractProps) => { return ( - - { t('polls.create.pollQuestion') } - - = ({ navigation }: IPrejoinProps) => { } }> - } value = { displayName } />