-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
212 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import React, {useState} from 'react'; | ||
import _ from 'underscore'; | ||
import TextInput from '@components/TextInput'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import getOperatingSystem from '@libs/getOperatingSystem'; | ||
import * as RoomNameInputUtils from '@libs/RoomNameInputUtils'; | ||
import CONST from '@src/CONST'; | ||
import * as roomNameInputPropTypes from './roomNameInputPropTypes'; | ||
|
||
function RoomNameInput({value, isFocused, autoFocus, disabled, forwardedRef, onBlur, shouldDelayFocus, onChangeText, onInputChange, ...restProps}) { | ||
const {translate} = useLocalize(); | ||
|
||
const keyboardType = getOperatingSystem() === CONST.OS.IOS ? CONST.KEYBOARD_TYPE.ASCII_CAPABLE : CONST.KEYBOARD_TYPE.VISIBLE_PASSWORD; | ||
const [selection, setSelection] = useState(); | ||
|
||
/** | ||
* Calls the onChangeText callback with a modified room name | ||
* @param {Event} event | ||
*/ | ||
const setModifiedRoomName = (event) => { | ||
const roomName = event.nativeEvent.text; | ||
const modifiedRoomName = RoomNameInputUtils.modifyRoomName(roomName); | ||
onChangeText(modifiedRoomName); | ||
|
||
// if custom component has onInputChange, use it to trigger changes (Form input) | ||
if (_.isFunction(onInputChange)) { | ||
onInputChange(modifiedRoomName); | ||
} | ||
|
||
// Prevent cursor jump behaviour: | ||
// Check if newRoomNameWithHash is the same as modifiedRoomName | ||
// If it is then the room name is valid (does not contain unallowed characters); no action required | ||
// If not then the room name contains unvalid characters and we must adjust the cursor position manually | ||
// Read more: https://github.com/Expensify/App/issues/12741 | ||
const oldRoomNameWithHash = value || ''; | ||
const newRoomNameWithHash = `${CONST.POLICY.ROOM_PREFIX}${roomName}`; | ||
if (modifiedRoomName !== newRoomNameWithHash) { | ||
const offset = modifiedRoomName.length - oldRoomNameWithHash.length; | ||
const newSelection = { | ||
start: selection.start + offset, | ||
end: selection.end + offset, | ||
}; | ||
setSelection(newSelection); | ||
} | ||
}; | ||
return ( | ||
<TextInput | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...restProps} | ||
ref={forwardedRef} | ||
disabled={disabled} | ||
label={translate('newRoomPage.roomName')} | ||
accessibilityLabel={translate('newRoomPage.roomName')} | ||
role={CONST.ACCESSIBILITY_ROLE.TEXT} | ||
placeholder={translate('newRoomPage.social')} | ||
autoCapitalize="none" | ||
value={value.substring(1)} | ||
onChange={setModifiedRoomName} | ||
selection={selection} | ||
onBlur={(event) => isFocused && onBlur(event)} | ||
shouldDelayFocus={shouldDelayFocus} | ||
autoFocus={isFocused && autoFocus} | ||
maxLength={CONST.REPORT.MAX_ROOM_NAME_LENGTH} | ||
onSelectionChange={(event) => setSelection(event.nativeEvent.selection)} | ||
spellCheck={false} | ||
shouldInterceptSwipe | ||
keyboardType={keyboardType} // this is a bit hacky solution to a RN issue https://github.com/facebook/react-native/issues/27449 | ||
/> | ||
); | ||
} | ||
|
||
RoomNameInput.propTypes = roomNameInputPropTypes.propTypes; | ||
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps; | ||
RoomNameInput.displayName = 'RoomNameInput'; | ||
|
||
const RoomNameInputWithRef = React.forwardRef((props, ref) => ( | ||
<RoomNameInput | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...props} | ||
forwardedRef={ref} | ||
/> | ||
)); | ||
|
||
RoomNameInputWithRef.displayName = 'RoomNameInputWithRef'; | ||
|
||
export default RoomNameInputWithRef; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from 'react'; | ||
import _ from 'underscore'; | ||
import TextInput from '@components/TextInput'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import getOperatingSystem from '@libs/getOperatingSystem'; | ||
import * as RoomNameInputUtils from '@libs/RoomNameInputUtils'; | ||
import CONST from '@src/CONST'; | ||
import * as roomNameInputPropTypes from './roomNameInputPropTypes'; | ||
|
||
function RoomNameInput({isFocused, autoFocus, disabled, errorText, forwardedRef, value, onBlur, onChangeText, onInputChange, shouldDelayFocus, ...restProps}) { | ||
const {translate} = useLocalize(); | ||
|
||
/** | ||
* Calls the onChangeText callback with a modified room name | ||
* @param {Event} event | ||
*/ | ||
const setModifiedRoomName = (event) => { | ||
const roomName = event.nativeEvent.text; | ||
const modifiedRoomName = RoomNameInputUtils.modifyRoomName(roomName); | ||
onChangeText(modifiedRoomName); | ||
|
||
// if custom component has onInputChange, use it to trigger changes (Form input) | ||
if (_.isFunction(onInputChange)) { | ||
onInputChange(modifiedRoomName); | ||
} | ||
}; | ||
|
||
const keyboardType = getOperatingSystem() === CONST.OS.IOS ? CONST.KEYBOARD_TYPE.ASCII_CAPABLE : CONST.KEYBOARD_TYPE.VISIBLE_PASSWORD; | ||
|
||
return ( | ||
<TextInput | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...restProps} | ||
ref={forwardedRef} | ||
disabled={disabled} | ||
label={translate('newRoomPage.roomName')} | ||
accessibilityLabel={translate('newRoomPage.roomName')} | ||
role={CONST.ACCESSIBILITY_ROLE.TEXT} | ||
prefixCharacter={CONST.POLICY.ROOM_PREFIX} | ||
placeholder={translate('newRoomPage.social')} | ||
onChange={setModifiedRoomName} | ||
value={value.substring(1)} // Since the room name always starts with a prefix, we omit the first character to avoid displaying it twice. | ||
errorText={errorText} | ||
maxLength={CONST.REPORT.MAX_ROOM_NAME_LENGTH} | ||
keyboardType={keyboardType} // this is a bit hacky solution to a RN issue https://github.com/facebook/react-native/issues/27449 | ||
onBlur={(event) => isFocused && onBlur(event)} | ||
autoFocus={isFocused && autoFocus} | ||
autoCapitalize="none" | ||
shouldDelayFocus={shouldDelayFocus} | ||
/> | ||
); | ||
} | ||
|
||
RoomNameInput.propTypes = roomNameInputPropTypes.propTypes; | ||
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps; | ||
RoomNameInput.displayName = 'RoomNameInput'; | ||
|
||
const RoomNameInputWithRef = React.forwardRef((props, ref) => ( | ||
<RoomNameInput | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...props} | ||
forwardedRef={ref} | ||
/> | ||
)); | ||
|
||
RoomNameInputWithRef.displayName = 'RoomNameInputWithRef'; | ||
|
||
export default RoomNameInputWithRef; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import PropTypes from 'prop-types'; | ||
|
||
const propTypes = { | ||
/** Callback to execute when the text input is modified correctly */ | ||
onChangeText: PropTypes.func, | ||
|
||
/** Room name to show in input field. This should include the '#' already prefixed to the name */ | ||
value: PropTypes.string, | ||
|
||
/** Whether we should show the input as disabled */ | ||
disabled: PropTypes.bool, | ||
|
||
/** Error text to show */ | ||
errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))]), | ||
|
||
/** A ref forwarded to the TextInput */ | ||
forwardedRef: PropTypes.func, | ||
|
||
/** The ID used to uniquely identify the input in a Form */ | ||
inputID: PropTypes.string, | ||
|
||
/** Callback that is called when the text input is blurred */ | ||
onBlur: PropTypes.func, | ||
|
||
/** AutoFocus */ | ||
autoFocus: PropTypes.bool, | ||
|
||
/** Whether we should wait before focusing the TextInput, useful when using transitions on Android */ | ||
shouldDelayFocus: PropTypes.bool, | ||
|
||
/** Whether navigation is focused */ | ||
isFocused: PropTypes.bool.isRequired, | ||
}; | ||
|
||
const defaultProps = { | ||
onChangeText: () => {}, | ||
value: '', | ||
disabled: false, | ||
errorText: '', | ||
forwardedRef: () => {}, | ||
|
||
inputID: undefined, | ||
onBlur: () => {}, | ||
autoFocus: false, | ||
shouldDelayFocus: false, | ||
}; | ||
|
||
export {propTypes, defaultProps}; |
Oops, something went wrong.