split up a bit of the mentions/emoji input

This commit is contained in:
Audric Ackermann 2022-02-08 16:09:58 +11:00
parent 2478a78794
commit 445852eca1
No known key found for this signature in database
GPG key ID: 999F434D76324AD4
5 changed files with 107 additions and 73 deletions

View file

@ -14,7 +14,6 @@ import {
import { AbortController } from 'abort-controller';
import { SessionQuotedMessageComposition } from '../SessionQuotedMessageComposition';
import { Mention, MentionsInput, SuggestionDataItem } from 'react-mentions';
import { MemberListItem } from '../../MemberListItem';
import autoBind from 'auto-bind';
import { getMediaPermissionsSettings } from '../../settings/SessionSettings';
import { getDraftForConversation, updateDraftForConversation } from '../SessionConversationDrafts';
@ -48,27 +47,13 @@ import {
StagedAttachmentImportedType,
StagedPreviewImportedType,
} from '../../../util/attachmentsUtil';
import { BaseEmoji, emojiIndex } from 'emoji-mart';
import styled from 'styled-components';
const queryEmojis = (query: string, _callback: any): Array<SuggestionDataItem> => {
if (query.length === 0 || !emojiIndex) {
return [];
}
const results = emojiIndex.search(query);
if (!results || !results.length) {
return [];
}
return results
.map(o => {
const onlyBaseEmokji = o as BaseEmoji;
return {
id: onlyBaseEmokji.native,
display: `${onlyBaseEmokji.native} ${onlyBaseEmokji.colons}`,
};
})
.slice(0, 8);
};
import {
cleanMentions,
mentionsRegex,
renderUserMentionRow,
styleForCompositionBoxSuggestions,
} from './UserMentions';
import { renderEmojiQuickResultRow, searchEmojiForQuery } from './EmojiQuickResult';
export interface ReplyingToMessageProps {
convoId: string;
@ -146,23 +131,7 @@ const sendMessageStyle = {
flexGrow: 1,
minHeight: '24px',
width: '100%',
suggestions: {
list: {
fontSize: 14,
boxShadow: 'rgba(0, 0, 0, 0.24) 0px 3px 8px',
backgroundColor: 'var(--color-cell-background)',
},
item: {
height: '100%',
paddingTop: '5px',
paddingBottom: '5px',
'&focused': {
backgroundColor: 'var(--color-clickable-hovered)',
},
},
},
...styleForCompositionBoxSuggestions,
};
const getDefaultState = (newConvoId?: string) => {
@ -176,8 +145,6 @@ const getDefaultState = (newConvoId?: string) => {
};
};
const mentionsRegex = /@\uFFD205[0-9a-f]{64}\uFFD7[^\uFFD2]+\uFFD2/gu;
const getSelectionBasedOnMentions = (draft: string, index: number) => {
// we have to get the real selectionStart/end of an index in the mentions box.
// this is kind of a pain as the mentions box has two inputs, one with the real text, and one with the extracted mentions
@ -235,23 +202,6 @@ const getSelectionBasedOnMentions = (draft: string, index: number) => {
return Number.MAX_SAFE_INTEGER;
};
// this is dirty but we have to replace all @(xxx) by @xxx manually here
function cleanMentions(text: string): string {
const matches = text.match(mentionsRegex);
let replacedMentions = text;
(matches || []).forEach(match => {
const replacedMention = match.substring(2, match.indexOf('\uFFD7'));
replacedMentions = replacedMentions.replace(match, `@${replacedMention}`);
});
return replacedMentions;
}
const EmojiQuickResult = styled.span<{ focused: boolean }>`
height: 30px;
width: 100%;
`;
class CompositionBoxInner extends React.Component<Props, State> {
private readonly textarea: React.RefObject<any>;
private readonly fileInput: React.RefObject<HTMLInputElement>;
@ -490,24 +440,15 @@ class CompositionBoxInner extends React.Component<Props, State> {
// this is only for the composition box visible content. The real stuff on the backend box is the @markup
displayTransform={(_id, display) => `@${display}`}
data={this.fetchUsersForGroup}
renderSuggestion={suggestion => (
<MemberListItem
isSelected={false}
key={suggestion.id}
pubkey={`${suggestion.id}`}
disableBg={true}
/>
)}
renderSuggestion={renderUserMentionRow}
/>
<Mention
trigger=":"
markup="__id__"
appendSpaceOnAdd={true}
regex={neverMatchingRegex}
data={queryEmojis}
renderSuggestion={(suggestion, _search, _highlightedDisplay, _index, focused) => (
<EmojiQuickResult focused={focused}>{suggestion.display}</EmojiQuickResult>
)}
data={searchEmojiForQuery}
renderSuggestion={renderEmojiQuickResultRow}
/>
</MentionsInput>
);

View file

@ -0,0 +1,44 @@
import React from 'react';
import { SuggestionDataItem } from 'react-mentions';
import styled from 'styled-components';
import { BaseEmoji, emojiIndex } from 'emoji-mart';
const EmojiQuickResult = styled.span`
width: 100%;
padding-inline-end: 20px;
padding-inline-start: 10px;
`;
const EmojiQuickResultIcon = styled.span`
padding-inline-end: 20px;
padding-inline-start: 10px;
font-size: 1.4em;
`;
const EmojiQuickResultText = styled.span``;
export const renderEmojiQuickResultRow = (suggestion: SuggestionDataItem) => {
return (
<EmojiQuickResult>
<EmojiQuickResultIcon>{suggestion.id}</EmojiQuickResultIcon>
<EmojiQuickResultText>{suggestion.display}</EmojiQuickResultText>
</EmojiQuickResult>
);
};
export const searchEmojiForQuery = (query: string): Array<SuggestionDataItem> => {
if (query.length === 0 || !emojiIndex) {
return [];
}
const results = emojiIndex.search(query);
if (!results || !results.length) {
return [];
}
return results
.map(o => {
const onlyBaseEmokji = o as BaseEmoji;
return {
id: onlyBaseEmokji.native,
display: onlyBaseEmokji.colons,
};
})
.slice(0, 8);
};

View file

@ -0,0 +1,49 @@
import React from 'react';
import { SuggestionDataItem } from 'react-mentions';
import { MemberListItem } from '../../MemberListItem';
export const styleForCompositionBoxSuggestions = {
suggestions: {
list: {
fontSize: 14,
boxShadow: 'rgba(0, 0, 0, 0.24) 0px 3px 8px',
backgroundColor: 'var(--color-cell-background)',
},
item: {
height: '100%',
paddingTop: '5px',
paddingBottom: '5px',
backgroundColor: 'var(--color-cell-background)',
transition: '0.25s',
'&focused': {
backgroundColor: 'var(--color-clickable-hovered)',
},
},
},
};
export const renderUserMentionRow = (suggestion: SuggestionDataItem) => {
return (
<MemberListItem
isSelected={false}
key={suggestion.id}
pubkey={`${suggestion.id}`}
disableBg={true}
/>
);
};
// this is dirty but we have to replace all @(xxx) by @xxx manually here
export function cleanMentions(text: string): string {
const matches = text.match(mentionsRegex);
let replacedMentions = text;
(matches || []).forEach(match => {
const replacedMention = match.substring(2, match.indexOf('\uFFD7'));
replacedMentions = replacedMentions.replace(match, `@${replacedMention}`);
});
return replacedMentions;
}
export const mentionsRegex = /@\uFFD205[0-9a-f]{64}\uFFD7[^\uFFD2]+\uFFD2/gu;

View file

@ -464,4 +464,4 @@ export type LocalizerKeys =
| 'searchFor...'
| 'joinedTheGroup'
| 'editGroupName'
| 'reportIssue'
| 'reportIssue';

View file

@ -19,12 +19,12 @@ function hasNormalCharacters(str: string) {
export function getEmojiSizeClass(str: string): SizeClassType {
if (hasNormalCharacters(str)) {
return 'default';
return 'small';
}
const emojiCount = getCountOfAllMatches(str);
if (emojiCount > 8) {
return 'default';
return 'small';
} else if (emojiCount > 6) {
return 'small';
} else if (emojiCount > 4) {