-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: Cursor moves to end after adding space in Room Name #12899
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
e8affd2
Fix: Cursor moves to end after adding space in Room Name
s77rt af7a844
Fixed lint errors
s77rt c5aca3a
moved propTypes and defaultProps to roomNameInputPropTypes.js
s77rt e246296
moved propTypes and defaultProps to roomNameInputPropTypes.js (2)
s77rt 494d6f1
Set default selection to undefined
s77rt 3ffbb01
Fixed lint issue withLocalizePropTypes not defined
s77rt f947319
Fix lint PropTypes is defined and never used
s77rt d36f0d8
Moved modifyRoomName function to RoomNameInputUtils
s77rt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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,81 @@ | ||
import React, {Component} from 'react'; | ||
import CONST from '../../CONST'; | ||
import withLocalize from '../withLocalize'; | ||
import TextInput from '../TextInput'; | ||
import * as roomNameInputPropTypes from './roomNameInputPropTypes'; | ||
import * as RoomNameInputUtils from '../../libs/RoomNameInputUtils'; | ||
|
||
class RoomNameInput extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.setModifiedRoomName = this.setModifiedRoomName.bind(this); | ||
this.setSelection = this.setSelection.bind(this); | ||
|
||
this.state = { | ||
selection: undefined, | ||
}; | ||
} | ||
|
||
/** | ||
* Calls the onChangeText callback with a modified room name | ||
* @param {Event} event | ||
*/ | ||
setModifiedRoomName(event) { | ||
const roomName = event.nativeEvent.text; | ||
const modifiedRoomName = RoomNameInputUtils.modifyRoomName(roomName); | ||
this.props.onChangeText(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 = this.props.value || ''; | ||
const newRoomNameWithHash = `${CONST.POLICY.ROOM_PREFIX}${roomName}`; | ||
if (modifiedRoomName !== newRoomNameWithHash) { | ||
const offset = modifiedRoomName.length - oldRoomNameWithHash.length; | ||
const selection = { | ||
start: this.state.selection.start + offset, | ||
end: this.state.selection.end + offset, | ||
}; | ||
this.setSelection(selection); | ||
} | ||
} | ||
|
||
/** | ||
* Set the selection | ||
* @param {Object} selection | ||
*/ | ||
setSelection(selection) { | ||
this.setState({selection}); | ||
} | ||
|
||
render() { | ||
return ( | ||
<TextInput | ||
ref={this.props.forwardedRef} | ||
disabled={this.props.disabled} | ||
label={this.props.translate('newRoomPage.roomName')} | ||
prefixCharacter={CONST.POLICY.ROOM_PREFIX} | ||
placeholder={this.props.translate('newRoomPage.social')} | ||
onChange={this.setModifiedRoomName} | ||
value={this.props.value.substring(1)} // Since the room name always starts with a prefix, we omit the first character to avoid displaying it twice. | ||
selection={this.state.selection} | ||
onSelectionChange={event => this.setSelection(event.nativeEvent.selection)} | ||
errorText={this.props.errorText} | ||
autoCapitalize="none" | ||
/> | ||
); | ||
} | ||
} | ||
|
||
RoomNameInput.propTypes = roomNameInputPropTypes.propTypes; | ||
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps; | ||
|
||
export default withLocalize( | ||
React.forwardRef((props, ref) => ( | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
<RoomNameInput {...props} forwardedRef={ref} /> | ||
)), | ||
); |
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,50 @@ | ||
import React, {Component} from 'react'; | ||
import CONST from '../../CONST'; | ||
import withLocalize from '../withLocalize'; | ||
import TextInput from '../TextInput'; | ||
import * as roomNameInputPropTypes from './roomNameInputPropTypes'; | ||
import * as RoomNameInputUtils from '../../libs/RoomNameInputUtils'; | ||
|
||
class RoomNameInput extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.setModifiedRoomName = this.setModifiedRoomName.bind(this); | ||
} | ||
|
||
/** | ||
* Calls the onChangeText callback with a modified room name | ||
* @param {Event} event | ||
*/ | ||
setModifiedRoomName(event) { | ||
const roomName = event.nativeEvent.text; | ||
const modifiedRoomName = RoomNameInputUtils.modifyRoomName(roomName); | ||
this.props.onChangeText(modifiedRoomName); | ||
} | ||
|
||
render() { | ||
return ( | ||
<TextInput | ||
ref={this.props.forwardedRef} | ||
disabled={this.props.disabled} | ||
label={this.props.translate('newRoomPage.roomName')} | ||
prefixCharacter={CONST.POLICY.ROOM_PREFIX} | ||
placeholder={this.props.translate('newRoomPage.social')} | ||
onChange={this.setModifiedRoomName} | ||
value={this.props.value.substring(1)} // Since the room name always starts with a prefix, we omit the first character to avoid displaying it twice. | ||
errorText={this.props.errorText} | ||
autoCapitalize="none" | ||
/> | ||
); | ||
} | ||
} | ||
|
||
RoomNameInput.propTypes = roomNameInputPropTypes.propTypes; | ||
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps; | ||
|
||
export default withLocalize( | ||
React.forwardRef((props, ref) => ( | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
<RoomNameInput {...props} forwardedRef={ref} /> | ||
)), | ||
); |
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,31 @@ | ||
import PropTypes from 'prop-types'; | ||
import {withLocalizePropTypes} from '../withLocalize'; | ||
|
||
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.string, | ||
|
||
...withLocalizePropTypes, | ||
|
||
/** A ref forwarded to the TextInput */ | ||
forwardedRef: PropTypes.func, | ||
}; | ||
|
||
const defaultProps = { | ||
onChangeText: () => {}, | ||
value: '', | ||
disabled: false, | ||
errorText: '', | ||
forwardedRef: () => {}, | ||
}; | ||
|
||
export {propTypes, defaultProps}; |
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,24 @@ | ||
import CONST from '../CONST'; | ||
|
||
/** | ||
* Modifies the room name to follow our conventions: | ||
* - Max length 80 characters | ||
* - Cannot not include space or special characters, and we automatically apply an underscore for spaces | ||
* - Must be lowercase | ||
* @param {String} roomName | ||
* @returns {String} | ||
*/ | ||
function modifyRoomName(roomName) { | ||
const modifiedRoomNameWithoutHash = roomName | ||
.replace(/ /g, '_') | ||
.replace(/[^a-zA-Z\d_]/g, '') | ||
.substr(0, CONST.REPORT.MAX_ROOM_NAME_LENGTH) | ||
.toLowerCase(); | ||
|
||
return `${CONST.POLICY.ROOM_PREFIX}${modifiedRoomNameWithoutHash}`; | ||
} | ||
|
||
export { | ||
// eslint-disable-next-line import/prefer-default-export | ||
modifyRoomName, | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We missed an edge case which caused #33652
When we select a text and paste longer text it preserves the selection.