make mentions work in react when emoji inserted inside at a rand pos

pull/1381/head
Audric Ackermann 4 years ago
parent b5af8eb215
commit c9e81454fb
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -12,7 +12,6 @@
min-width: 20px;
}
.existing-member {
color: green;
}
@ -42,7 +41,6 @@
}
}
.invisible {
visibility: hidden;
}
@ -69,8 +67,6 @@
}
}
.mention-profile-name {
color: rgb(194, 244, 255);
background-color: rgb(66, 121, 150);

@ -28,7 +28,13 @@ export class MemberItem extends React.Component<MemberItemProps> {
}
public render() {
const {authorProfileName: name, authorPhoneNumber: pubkey, selected, existingMember, checkmarked} = this.props.member;
const {
authorProfileName: name,
authorPhoneNumber: pubkey,
selected,
existingMember,
checkmarked,
} = this.props.member;
const shortPubkey = window.shortenPubkey(pubkey);
let markType: 'none' | 'kicked' | 'added' | 'existing' = 'none';
@ -80,7 +86,6 @@ export class MemberItem extends React.Component<MemberItemProps> {
</div>
);
}
private handleClick() {
this.props.onClicked(this.props.member);
}

@ -15,6 +15,7 @@ const SessionToastContainerPrivate = () => {
draggable={true}
pauseOnHover={true}
transition={Slide}
limit={5}
/>
);
};

@ -124,7 +124,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
private emojiPanel: any;
private linkPreviewAbortController?: AbortController;
private container: any;
private mentionsData: Array<{ display: string; id: string }>;
private readonly mentionsRegex = /@\(05[0-9a-f]{64}\)/g;
constructor(props: any) {
super(props);
@ -132,7 +132,6 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.textarea = props.textarea;
this.fileInput = React.createRef();
this.mentionsData = [];
// Emojis
this.emojiPanel = null;
@ -143,9 +142,10 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.renderRecordingView = this.renderRecordingView.bind(this);
this.renderCompositionView = this.renderCompositionView.bind(this);
this.renderTextArea = this.renderTextArea.bind(this);
this.renderQuotedMessage = this.renderQuotedMessage.bind(this);
this.renderStagedLinkPreview = this.renderStagedLinkPreview.bind(this);
this.renderStagedLinkPreview = this.renderStagedLinkPreview.bind(this);
this.renderAttachmentsStaged = this.renderAttachmentsStaged.bind(this);
// Recording view functions
@ -185,7 +185,6 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// reset the state on new conversation key
if (prevProps.conversationKey !== this.props.conversationKey) {
this.setState(getDefaultState());
this.mentionsData = [];
}
}
@ -248,20 +247,15 @@ export class SessionCompositionBox extends React.Component<Props, State> {
);
}
private renderCompositionView() {
private isTypingEnabled(): boolean {
const { isBlocked, isKickedFromGroup, leftGroup, isPrivate } = this.props;
const { showEmojiPanel, message } = this.state;
const typingEnabled = !(isBlocked || isKickedFromGroup || leftGroup);
const { i18n } = window;
const messagePlaceHolder = isKickedFromGroup
? i18n('youGotKickedFromGroup')
: leftGroup
? i18n('youLeftTheGroup')
: isBlocked && isPrivate
? i18n('unblockToSend')
: isBlocked && !isPrivate
? i18n('unblockGroupToSend')
: i18n('sendMessage');
return !(isBlocked || isKickedFromGroup || leftGroup);
}
private renderCompositionView() {
const { showEmojiPanel } = this.state;
const typingEnabled = this.isTypingEnabled();
return (
<>
@ -293,13 +287,66 @@ export class SessionCompositionBox extends React.Component<Props, State> {
<div
className="send-message-input"
role="main"
onClick={this.focusCompositionBox}
onClick={this.focusCompositionBox} // used to focus on the textarea when clicking in its container
ref={el => {
this.container = el;
}}
>
{this.renderTextArea()}
</div>
{typingEnabled && (
<SessionIconButton
iconType={SessionIconType.Emoji}
iconSize={SessionIconSize.Large}
onClick={this.toggleEmojiPanel}
/>
)}
<div className="send-message-button">
<SessionIconButton
iconType={SessionIconType.Send}
iconSize={SessionIconSize.Large}
iconRotation={90}
onClick={this.onSendMessage}
/>
</div>
{typingEnabled && (
<div
ref={ref => (this.emojiPanel = ref)}
onKeyDown={this.onKeyDown}
role="button"
>
{showEmojiPanel && (
<SessionEmojiPanel
onEmojiClicked={this.onEmojiClick}
show={showEmojiPanel}
/>
)}
</div>
)}
</>
);
}
private renderTextArea() {
const { i18n } = window;
const { message } = this.state;
const { isKickedFromGroup, leftGroup, isPrivate, isBlocked } = this.props;
const messagePlaceHolder = isKickedFromGroup
? i18n('youGotKickedFromGroup')
: leftGroup
? i18n('youLeftTheGroup')
: isBlocked && isPrivate
? i18n('unblockToSend')
: isBlocked && !isPrivate
? i18n('unblockGroupToSend')
: i18n('sendMessage');
const typingEnabled = this.isTypingEnabled();
return (
<MentionsInput
value={this.state.message}
value={message}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
placeholder={messagePlaceHolder}
@ -308,16 +355,15 @@ export class SessionCompositionBox extends React.Component<Props, State> {
disabled={!typingEnabled}
maxLength={Constants.CONVERSATION.MAX_MESSAGE_BODY_LENGTH}
rows={1}
// maxRows={3}
style={sendMessageStyle}
suggestionsPortalHost={this.container}
allowSuggestionsAboveCursor={true}
allowSuggestionsAboveCursor={true} // if only one suggestion, it might be rendered below
>
<Mention
appendSpaceOnAdd={true}
markup="@(__id__)" // @__id__ does not work, see cleanMentions()
trigger="@"
displayTransform={id => `@${id}`}
displayTransform={id => `@(${id})`}
data={this.fetchUsersForGroup}
renderSuggestion={(
suggestion,
@ -347,41 +393,9 @@ export class SessionCompositionBox extends React.Component<Props, State> {
)}
/>
</MentionsInput>
</div>
{typingEnabled && (
<SessionIconButton
iconType={SessionIconType.Emoji}
iconSize={SessionIconSize.Large}
onClick={this.toggleEmojiPanel}
/>
)}
<div className="send-message-button">
<SessionIconButton
iconType={SessionIconType.Send}
iconSize={SessionIconSize.Large}
iconRotation={90}
onClick={this.onSendMessage}
/>
</div>
{typingEnabled && (
<div
ref={ref => (this.emojiPanel = ref)}
onKeyDown={this.onKeyDown}
role="button"
>
{showEmojiPanel && (
<SessionEmojiPanel
onEmojiClicked={this.onEmojiClick}
show={showEmojiPanel}
/>
)}
</div>
)}
</>
);
}
private fetchUsersForGroup(query: any, callback: any) {
if (!query) {
return;
@ -451,13 +465,12 @@ export class SessionCompositionBox extends React.Component<Props, State> {
.filter(d =>
d.authorProfileName?.toLowerCase()?.includes(query.toLowerCase())
);
// Transform the users to what react-mentions expects
// Transform the users to what react-mentions expects
const mentionsData = members.map(user => ({
display: user.authorProfileName,
id: user.authorPhoneNumber,
}));
this.mentionsData = mentionsData;
callback(mentionsData);
}
@ -654,10 +667,9 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// tslint:disable-next-line: cyclomatic-complexity
private async onSendMessage() {
// replace all @(xxx) by @xxx
// this is dirty but we have to replace all @(xxx) by @xxx manually here
const cleanMentions = (text: string): string => {
const mentionRegex = /@\(05[0-9a-f]{64}\)/g;
const matches = text.match(mentionRegex);
const matches = text.match(this.mentionsRegex);
let replacedMentions = text;
(matches || []).forEach(match => {
const replacedMention = match.substring(2, match.length - 1);
@ -847,13 +859,14 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.setState({ message });
}
private onEmojiClick({ colons, native }: { colons: string; native: string }) {
private onEmojiClick({ colons }: { colons: string }) {
const messageBox = this.textarea.current;
if (!messageBox) {
return;
}
const { message } = this.state;
const currentSelectionStart = Number(messageBox.selectionStart);
const currentSelectionEnd = Number(messageBox.selectionEnd);

Loading…
Cancel
Save