Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Enlarge emoji in composer #7602

Merged
merged 7 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions res/css/views/elements/_RichText.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ a.mx_Pill {
margin-right: 0.24rem;
}

.mx_Emoji {
font-size: 1.8rem;
vertical-align: bottom;
}

.mx_Markdown_BOLD {
font-weight: bold;
}
Expand Down
2 changes: 2 additions & 0 deletions res/css/views/rooms/_EventBubbleTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ limitations under the License.
.mx_EventTile_line {
width: fit-content;
max-width: 70%;
// fixed line height to prevent emoji from being taller than text
line-height: $font-18px;
}

> .mx_SenderProfile {
Expand Down
7 changes: 1 addition & 6 deletions res/css/views/rooms/_EventTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,6 @@ $left-gutter: 64px;
overflow-y: hidden;
}

.mx_EventTile_Emoji {
font-size: 1.8rem;
vertical-align: bottom;
}

&.mx_EventTile_selected .mx_EventTile_line,
&:hover .mx_EventTile_line {
border-top-left-radius: 4px;
Expand Down Expand Up @@ -391,7 +386,7 @@ $left-gutter: 64px;
position: absolute;
}

.mx_EventTile_bigEmoji .mx_EventTile_Emoji {
.mx_EventTile_bigEmoji .mx_Emoji {
font-size: 48px !important;
line-height: 57px;
}
Expand Down
2 changes: 2 additions & 0 deletions res/css/views/rooms/_SendMessageComposer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ limitations under the License.
display: flex;
flex-direction: column;
font-size: $font-14px;
// fixed line height to prevent emoji from being taller than text
line-height: calc(1.2 * $font-14px);
justify-content: center;
margin-right: 6px;
// don't grow wider than available space
Expand Down
7 changes: 3 additions & 4 deletions src/HtmlUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)
* Uses a much, much simpler regex than emojibase's so will give false
* positives, but useful for fast-path testing strings to see if they
* need emojification.
* unicodeToImage uses this function.
*/
function mightContainEmoji(str: string): boolean {
export function mightContainEmoji(str: string): boolean {
return SURROGATE_PAIR_PATTERN.test(str) || SYMBOL_PATTERN.test(str);
}

Expand Down Expand Up @@ -404,9 +403,9 @@ export interface IOptsReturnString extends IOpts {
}

const emojiToHtmlSpan = (emoji: string) =>
`<span class='mx_EventTile_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
`<span class='mx_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
const emojiToJsxSpan = (emoji: string, key: number) =>
<span key={key} className='mx_EventTile_Emoji' title={unicodeToShortcode(emoji)}>{ emoji }</span>;
<span key={key} className='mx_Emoji' title={unicodeToShortcode(emoji)}>{ emoji }</span>;

/**
* Wraps emojis in <span> to style them separately from the rest of message. Consecutive emojis (and modifiers) are wrapped
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/rooms/BasicMessageComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>

// this returns the amount of added/removed characters during the replace
// so the caret position can be adjusted.
return range.replace([partCreator.plain(data.unicode)]);
return range.replace([partCreator.emoji(data.unicode)]);
}
}
}
Expand Down Expand Up @@ -831,7 +831,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
const caret = this.getCaret();
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
model.transform(() => {
const addedLen = model.insert([partCreator.plain(text)], position);
const addedLen = model.insert(partCreator.plainWithEmoji(text), position);
return model.positionForOffset(caret.offset + addedLen, true);
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/editor/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class AutocompleteWrapperModel {
return [(this.partCreator as CommandPartCreator).command(text)];
default:
// used for emoji and other plain text completion replacement
return [this.partCreator.plain(text)];
return this.partCreator.plainWithEmoji(text);
}
}
}
10 changes: 5 additions & 5 deletions src/editor/caret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function getLineAndNodePosition(model: EditorModel, caretPosition: IPosit
offset = 0;
} else {
// move caret out of uneditable part (into caret node, or empty line br) if needed
({ nodeIndex, offset } = moveOutOfUneditablePart(parts, partIndex, nodeIndex, offset));
({ nodeIndex, offset } = moveOutOfUnselectablePart(parts, partIndex, nodeIndex, offset));
}
return { lineIndex, nodeIndex, offset };
}
Expand All @@ -123,7 +123,7 @@ function findNodeInLineForPart(parts: Part[], partIndex: number) {
nodeIndex += 1;
}
// only jump over caret node if we're not at our destination node already,
// as we'll assume in moveOutOfUneditablePart that nodeIndex
// as we'll assume in moveOutOfUnselectablePart that nodeIndex
// refers to the node corresponding to the part,
// and not an adjacent caret node
if (i < partIndex) {
Expand All @@ -140,10 +140,10 @@ function findNodeInLineForPart(parts: Part[], partIndex: number) {
return { lineIndex, nodeIndex };
}

function moveOutOfUneditablePart(parts: Part[], partIndex: number, nodeIndex: number, offset: number) {
// move caret before or after uneditable part
function moveOutOfUnselectablePart(parts: Part[], partIndex: number, nodeIndex: number, offset: number) {
// move caret before or after unselectable part
const part = parts[partIndex];
if (part && !part.canEdit) {
if (part && !part.acceptsCaret) {
if (offset === 0) {
nodeIndex -= 1;
const prevPart = parts[partIndex - 1];
Expand Down
38 changes: 19 additions & 19 deletions src/editor/deserialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function parseAtRoomMentions(text: string, partCreator: PartCreator): Part[] {
const parts: Part[] = [];
text.split(ATROOM).forEach((textPart, i, arr) => {
if (textPart.length) {
parts.push(partCreator.plain(textPart));
parts.push(...partCreator.plainWithEmoji(textPart));
}
// it's safe to never append @room after the last textPart
// as split will report an empty string at the end if
Expand All @@ -42,28 +42,28 @@ function parseAtRoomMentions(text: string, partCreator: PartCreator): Part[] {
return parts;
}

function parseLink(a: HTMLAnchorElement, partCreator: PartCreator): Part {
function parseLink(a: HTMLAnchorElement, partCreator: PartCreator): Part[] {
const { href } = a;
const resourceId = getPrimaryPermalinkEntity(href); // The room/user ID
const prefix = resourceId ? resourceId[0] : undefined; // First character of ID
switch (prefix) {
case "@":
return partCreator.userPill(a.textContent, resourceId);
return [partCreator.userPill(a.textContent, resourceId)];
case "#":
return partCreator.roomPill(resourceId);
return [partCreator.roomPill(resourceId)];
default: {
if (href === a.textContent) {
return partCreator.plain(a.textContent);
return partCreator.plainWithEmoji(a.textContent);
} else {
return partCreator.plain(`[${a.textContent.replace(/[[\\\]]/g, c => "\\" + c)}](${href})`);
return partCreator.plainWithEmoji(`[${a.textContent.replace(/[[\\\]]/g, c => "\\" + c)}](${href})`);
}
}
}
}

function parseImage(img: HTMLImageElement, partCreator: PartCreator): Part {
function parseImage(img: HTMLImageElement, partCreator: PartCreator): Part[] {
const { src } = img;
return partCreator.plain(`![${img.alt.replace(/[[\\\]]/g, c => "\\" + c)}](${src})`);
return partCreator.plainWithEmoji(`![${img.alt.replace(/[[\\\]]/g, c => "\\" + c)}](${src})`);
}

function parseCodeBlock(n: HTMLElement, partCreator: PartCreator): Part[] {
Expand All @@ -79,7 +79,7 @@ function parseCodeBlock(n: HTMLElement, partCreator: PartCreator): Part[] {
}
const preLines = ("```" + language + "\n" + n.textContent + "```").split("\n");
preLines.forEach((l, i) => {
parts.push(partCreator.plain(l));
parts.push(...partCreator.plainWithEmoji(l));
if (i < preLines.length - 1) {
parts.push(partCreator.newline());
}
Expand Down Expand Up @@ -126,21 +126,21 @@ function parseElement(
partCreator.newline(),
];
case "EM":
return partCreator.plain(`_${n.textContent}_`);
return partCreator.plainWithEmoji(`_${n.textContent}_`);
case "STRONG":
return partCreator.plain(`**${n.textContent}**`);
return partCreator.plainWithEmoji(`**${n.textContent}**`);
case "PRE":
return parseCodeBlock(n, partCreator);
case "CODE":
return partCreator.plain(`\`${n.textContent}\``);
return partCreator.plainWithEmoji(`\`${n.textContent}\``);
case "DEL":
return partCreator.plain(`<del>${n.textContent}</del>`);
return partCreator.plainWithEmoji(`<del>${n.textContent}</del>`);
case "SUB":
return partCreator.plain(`<sub>${n.textContent}</sub>`);
return partCreator.plainWithEmoji(`<sub>${n.textContent}</sub>`);
case "SUP":
return partCreator.plain(`<sup>${n.textContent}</sup>`);
return partCreator.plainWithEmoji(`<sup>${n.textContent}</sup>`);
case "U":
return partCreator.plain(`<u>${n.textContent}</u>`);
return partCreator.plainWithEmoji(`<u>${n.textContent}</u>`);
case "LI": {
const BASE_INDENT = 4;
const depth = state.listDepth - 1;
Expand Down Expand Up @@ -171,9 +171,9 @@ function parseElement(
((SdkConfig.get()['latex_maths_delims'] || {})['inline'] || {})['right'] || "\\)" :
((SdkConfig.get()['latex_maths_delims'] || {})['display'] || {})['right'] || "\\]";
const tex = n.getAttribute("data-mx-maths");
return partCreator.plain(delimLeft + tex + delimRight);
return partCreator.plainWithEmoji(delimLeft + tex + delimRight);
} else if (!checkDescendInto(n)) {
return partCreator.plain(n.textContent);
return partCreator.plainWithEmoji(n.textContent);
}
break;
}
Expand All @@ -186,7 +186,7 @@ function parseElement(
default:
// don't textify block nodes we'll descend into
if (!checkDescendInto(n)) {
return partCreator.plain(n.textContent);
return partCreator.plainWithEmoji(n.textContent);
}
}
}
Expand Down
Loading