Update to new message bubble reactions design
This commit is contained in:
parent
682ac656c6
commit
01d4aa0772
7 changed files with 482 additions and 460 deletions
|
@ -1152,6 +1152,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"notificationReactionMessage": {
|
||||||
|
"message": "$sender$ reacted $emoji$ to: $message$",
|
||||||
|
"placeholders": {
|
||||||
|
"sender": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "John"
|
||||||
|
},
|
||||||
|
"emoji": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "👍"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"content": "$3",
|
||||||
|
"example": "Sounds good."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notificationReactionMessageMostRecent": {
|
||||||
|
"message": "Most recent: $sender$ reacted $emoji$ to: $message$",
|
||||||
|
"placeholders": {
|
||||||
|
"sender": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "John"
|
||||||
|
},
|
||||||
|
"emoji": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "👍"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"content": "$3",
|
||||||
|
"example": "Sounds good."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sendFailed": {
|
"sendFailed": {
|
||||||
"message": "Send failed",
|
"message": "Send failed",
|
||||||
"description": "Shown on outgoing message if it fails to send"
|
"description": "Shown on outgoing message if it fails to send"
|
||||||
|
|
|
@ -126,9 +126,10 @@
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
title = last.title;
|
title = last.title;
|
||||||
if (last.reaction) {
|
if (last.reaction) {
|
||||||
message = i18n('notificationReaction', [
|
message = i18n('notificationReactionMessage', [
|
||||||
last.title,
|
last.title,
|
||||||
last.reaction.emoji,
|
last.reaction.emoji,
|
||||||
|
last.message,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
@ -136,9 +137,10 @@
|
||||||
}
|
}
|
||||||
} else if (last.reaction) {
|
} else if (last.reaction) {
|
||||||
title = newMessageCountLabel;
|
title = newMessageCountLabel;
|
||||||
message = i18n('notificationReactionMostRecent', [
|
message = i18n('notificationReactionMessageMostRecent', [
|
||||||
last.title,
|
last.title,
|
||||||
last.reaction.emoji,
|
last.reaction.emoji,
|
||||||
|
last.message,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
title = newMessageCountLabel;
|
title = newMessageCountLabel;
|
||||||
|
|
|
@ -90,16 +90,10 @@
|
||||||
|
|
||||||
.module-message__buttons--incoming {
|
.module-message__buttons--incoming {
|
||||||
left: calc(100% + 8px);
|
left: calc(100% + 8px);
|
||||||
&.module-message__buttons--has-reactions {
|
|
||||||
padding-left: 40px - 12px; // Adjust 40px by 12px margin on the button
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.module-message__buttons--outgoing {
|
.module-message__buttons--outgoing {
|
||||||
right: calc(100% + 8px);
|
right: calc(100% + 8px);
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
&.module-message__buttons--has-reactions {
|
|
||||||
padding-right: 40px - 12px; // Adjust 40px by 12px margin on the button
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-message__buttons__download {
|
.module-message__buttons__download {
|
||||||
|
@ -1096,6 +1090,14 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
margin-bottom: -3px;
|
margin-bottom: -3px;
|
||||||
|
|
||||||
|
&--outgoing {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--with-reactions {
|
||||||
|
margin-bottom: -2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// With an image and no caption, this section needs to be on top of the image overlay
|
// With an image and no caption, this section needs to be on top of the image overlay
|
||||||
|
@ -1171,10 +1173,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-message__metadata__spacer {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-message__metadata__status-icon {
|
.module-message__metadata__status-icon {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
@ -1342,43 +1340,57 @@
|
||||||
|
|
||||||
.module-message__reactions {
|
.module-message__reactions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
bottom: 0px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
height: 100%;
|
height: 22px;
|
||||||
|
display: flex;
|
||||||
&--incoming {
|
|
||||||
right: -28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--outgoing {
|
|
||||||
left: -28px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-message__reactions__reaction {
|
.module-message__reactions__reaction {
|
||||||
@include button-reset;
|
@include button-reset;
|
||||||
|
|
||||||
width: 33px;
|
min-width: 28px;
|
||||||
height: 33px;
|
height: 22px;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-radius: 33px;
|
border-radius: 33px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
position: absolute;
|
&--with-count {
|
||||||
top: 0;
|
min-width: 40px;
|
||||||
|
|
||||||
&:first-of-type {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&--incoming {
|
&__count {
|
||||||
right: 0;
|
@include font-caption-bold;
|
||||||
}
|
|
||||||
|
|
||||||
&--outgoing {
|
margin-left: 4px;
|
||||||
left: 0;
|
|
||||||
|
&--no-emoji {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-25;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--is-me {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-75;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-15;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include ios-theme {
|
||||||
|
color: $color-white-alpha-90;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
@ -7633,6 +7645,10 @@ button.module-image__border-overlay:focus {
|
||||||
.module-message__container {
|
.module-message__container {
|
||||||
// 2px to allow for 1px border
|
// 2px to allow for 1px border
|
||||||
max-width: 302px;
|
max-width: 302px;
|
||||||
|
|
||||||
|
&--with-reactions {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Spec: container > 438px and container < 593px */
|
/* Spec: container > 438px and container < 593px */
|
||||||
|
|
|
@ -449,369 +449,253 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||||
|
|
||||||
### Reactions
|
### Reactions
|
||||||
|
|
||||||
#### One Reaction
|
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
<util.ConversationContext>
|
||||||
<div className="module-message-container">
|
{[
|
||||||
<Message
|
{ reactions: [{ emoji: '👍', from: { id: '+14155552671' } }] },
|
||||||
direction="incoming"
|
{
|
||||||
status="delivered"
|
reactions: [
|
||||||
authorColor="red"
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Jack Sparrow' } },
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
{
|
||||||
emoji: '👍',
|
emoji: '😂',
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
from: { id: '+14155552672', profileName: 'Davy Jones' },
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="outgoing"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### One Reaction - Ours
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="incoming"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="outgoing"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Multiple reactions, ordered by most common then most recent
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="incoming"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Jack Sparrow' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
{
|
{
|
||||||
emoji: '😮',
|
emoji: '😮',
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
from: { id: '+14155552673', profileName: 'Joel Ferrari' },
|
||||||
timestamp: 2,
|
|
||||||
},
|
},
|
||||||
]}
|
],
|
||||||
/>
|
},
|
||||||
</div>
|
{
|
||||||
<div className="module-message-container">
|
reactions: [
|
||||||
<Message
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Jack Sparrow' } },
|
||||||
direction="outgoing"
|
{ emoji: '😂', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
status="delivered"
|
{ emoji: '😮', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
authorColor="red"
|
{ emoji: '😡', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
timestamp={Date.now()}
|
{ emoji: '👎', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
{ emoji: '❤️', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
i18n={util.i18n}
|
],
|
||||||
reactions={[
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😡', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👎', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😮', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😮', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😮', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😡', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👎', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
reactions: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
{
|
{
|
||||||
emoji: '👍',
|
emoji: '👍',
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
from: { isMe: true, id: '+14155552671', name: 'Amelia Briggs' },
|
||||||
timestamp: 1,
|
|
||||||
},
|
},
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😡', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
{
|
{
|
||||||
emoji: '👍',
|
emoji: '😂',
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
from: { isMe: true, id: '+14155552674', name: 'Amelia Briggs' },
|
||||||
timestamp: 1,
|
|
||||||
},
|
},
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😡', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
{
|
{
|
||||||
emoji: '😡',
|
emoji: '😡',
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
from: { isMe: true, id: '+14155552677', name: 'Amelia Briggs' },
|
||||||
timestamp: 1,
|
|
||||||
},
|
},
|
||||||
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
outgoing: true,
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '😂', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
outgoing: true,
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '😡', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
outgoing: true,
|
||||||
|
reactions: [
|
||||||
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
{
|
{
|
||||||
emoji: '😮',
|
emoji: '😂',
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
from: { isMe: true, id: '+14155552674', name: 'Amelia Briggs' },
|
||||||
timestamp: 2,
|
|
||||||
},
|
},
|
||||||
]}
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
/>
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
</div>
|
{ emoji: '😡', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
</util.ConversationContext>
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
```
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
|
],
|
||||||
#### Multiple reactions, ours is most recent/common
|
},
|
||||||
|
{
|
||||||
```jsx
|
outgoing: true,
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
short: true,
|
||||||
<div className="module-message-container">
|
reactions: [
|
||||||
<Message
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
direction="incoming"
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
status="delivered"
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
authorColor="red"
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
timestamp={Date.now()}
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
i18n={util.i18n}
|
{ emoji: '😡', from: { id: '+14155552677', name: 'Amelia Briggs' } },
|
||||||
reactions={[
|
{ emoji: '👎', from: { id: '+14155552678', name: 'Amelia Briggs' } },
|
||||||
{
|
{ emoji: '❤️', from: { id: '+14155552679', name: 'Amelia Briggs' } },
|
||||||
emoji: '👍',
|
],
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Amelia Briggs' },
|
},
|
||||||
timestamp: 1,
|
{
|
||||||
},
|
outgoing: true,
|
||||||
{
|
short: true,
|
||||||
emoji: '👍',
|
reactions: [
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
timestamp: 1,
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
},
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
{
|
{ emoji: '😂', from: { id: '+14155552674', name: 'Amelia Briggs' } },
|
||||||
emoji: '😡',
|
{ emoji: '😂', from: { id: '+14155552675', name: 'Amelia Briggs' } },
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
{ emoji: '😂', from: { id: '+14155552676', name: 'Amelia Briggs' } },
|
||||||
timestamp: 1,
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
emoji: '😮',
|
outgoing: true,
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
short: true,
|
||||||
timestamp: 2,
|
reactions: [
|
||||||
},
|
{ emoji: '👍', from: { id: '+14155552671', name: 'Amelia Briggs' } },
|
||||||
]}
|
{ emoji: '👍', from: { id: '+14155552672', name: 'Amelia Briggs' } },
|
||||||
/>
|
{ emoji: '👍', from: { id: '+14155552673', name: 'Amelia Briggs' } },
|
||||||
</div>
|
],
|
||||||
<div className="module-message-container">
|
},
|
||||||
<Message
|
].map((spec, i) => (
|
||||||
direction="outgoing"
|
<div key={i} className="module-message-container">
|
||||||
status="delivered"
|
<Message
|
||||||
authorColor="red"
|
direction={spec.outgoing ? 'outgoing' : 'incoming'}
|
||||||
timestamp={Date.now()}
|
status="delivered"
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
authorColor="light_green"
|
||||||
i18n={util.i18n}
|
timestamp={Date.now()}
|
||||||
reactions={[
|
text={
|
||||||
{
|
spec.short
|
||||||
emoji: '👍',
|
? 'hahaha'
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
: "I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
||||||
timestamp: 1,
|
}
|
||||||
},
|
reactions={spec.reactions}
|
||||||
{
|
i18n={util.i18n}
|
||||||
emoji: '👍',
|
/>
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Joel Ferrari' },
|
</div>
|
||||||
timestamp: 1,
|
))}
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😮',
|
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
|
||||||
timestamp: 2,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Multiple reactions, ours not on top
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="incoming"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😮',
|
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Rick Owens' },
|
|
||||||
timestamp: 2,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="outgoing"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="I'd like to order one large phone with extra phones please. cell phone, no no no rotary... and payphone on half."
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😮',
|
|
||||||
from: { id: '+14155552671', isMe: true, name: 'Rick Owens' },
|
|
||||||
timestamp: 2,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Small message
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="incoming"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="Burgertime!"
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😮',
|
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
|
||||||
timestamp: 2,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="module-message-container">
|
|
||||||
<Message
|
|
||||||
direction="outgoing"
|
|
||||||
status="delivered"
|
|
||||||
authorColor="red"
|
|
||||||
timestamp={Date.now()}
|
|
||||||
text="Burgertime!"
|
|
||||||
i18n={util.i18n}
|
|
||||||
reactions={[
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Amelia Briggs' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '👍',
|
|
||||||
from: { id: '+14155552671', name: 'Joel Ferrari' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😡',
|
|
||||||
from: { id: '+14155552671', name: 'Adam Burrell' },
|
|
||||||
timestamp: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
emoji: '😮',
|
|
||||||
from: { id: '+14155552671', name: 'Rick Owens' },
|
|
||||||
timestamp: 2,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</util.ConversationContext>
|
</util.ConversationContext>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ReactDOM, { createPortal } from 'react-dom';
|
import ReactDOM, { createPortal } from 'react-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Measure from 'react-measure';
|
import Measure from 'react-measure';
|
||||||
import { clamp, groupBy, orderBy, take } from 'lodash';
|
import { drop, groupBy, orderBy, take } from 'lodash';
|
||||||
import { Manager, Popper, Reference } from 'react-popper';
|
import { Manager, Popper, Reference } from 'react-popper';
|
||||||
|
|
||||||
import { Avatar } from '../Avatar';
|
import { Avatar } from '../Avatar';
|
||||||
|
@ -161,11 +161,12 @@ interface State {
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
prevSelectedCounter: number;
|
prevSelectedCounter: number;
|
||||||
|
|
||||||
reactionsHeight: number;
|
|
||||||
reactionViewerRoot: HTMLDivElement | null;
|
reactionViewerRoot: HTMLDivElement | null;
|
||||||
reactionPickerRoot: HTMLDivElement | null;
|
reactionPickerRoot: HTMLDivElement | null;
|
||||||
|
|
||||||
isWide: boolean;
|
isWide: boolean;
|
||||||
|
|
||||||
|
containerWidth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXPIRATION_CHECK_MINIMUM = 2000;
|
const EXPIRATION_CHECK_MINIMUM = 2000;
|
||||||
|
@ -199,11 +200,12 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
isSelected: props.isSelected,
|
isSelected: props.isSelected,
|
||||||
prevSelectedCounter: props.isSelectedCounter,
|
prevSelectedCounter: props.isSelectedCounter,
|
||||||
|
|
||||||
reactionsHeight: 0,
|
|
||||||
reactionViewerRoot: null,
|
reactionViewerRoot: null,
|
||||||
reactionPickerRoot: null,
|
reactionPickerRoot: null,
|
||||||
|
|
||||||
isWide: this.wideMl.matches,
|
isWide: this.wideMl.matches,
|
||||||
|
|
||||||
|
containerWidth: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +372,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line cyclomatic-complexity
|
||||||
public renderMetadata() {
|
public renderMetadata() {
|
||||||
const {
|
const {
|
||||||
collapseMetadata,
|
collapseMetadata,
|
||||||
|
@ -379,6 +382,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
i18n,
|
i18n,
|
||||||
isSticker,
|
isSticker,
|
||||||
isTapToViewExpired,
|
isTapToViewExpired,
|
||||||
|
reactions,
|
||||||
status,
|
status,
|
||||||
text,
|
text,
|
||||||
textPending,
|
textPending,
|
||||||
|
@ -391,6 +395,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
const isShowingImage = this.isShowingImage();
|
const isShowingImage = this.isShowingImage();
|
||||||
const withImageNoCaption = Boolean(!isSticker && !text && isShowingImage);
|
const withImageNoCaption = Boolean(!isSticker && !text && isShowingImage);
|
||||||
|
const withReactions = reactions && reactions.length > 0;
|
||||||
const showError = status === 'error' && direction === 'outgoing';
|
const showError = status === 'error' && direction === 'outgoing';
|
||||||
const metadataDirection = isSticker ? undefined : direction;
|
const metadataDirection = isSticker ? undefined : direction;
|
||||||
|
|
||||||
|
@ -398,12 +403,13 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'module-message__metadata',
|
'module-message__metadata',
|
||||||
|
`module-message__metadata--${direction}`,
|
||||||
|
withReactions ? 'module-message__metadata--with-reactions' : null,
|
||||||
withImageNoCaption
|
withImageNoCaption
|
||||||
? 'module-message__metadata--with-image-no-caption'
|
? 'module-message__metadata--with-image-no-caption'
|
||||||
: null
|
: null
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="module-message__metadata__spacer" />
|
|
||||||
{showError ? (
|
{showError ? (
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -991,9 +997,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { reactions } = this.props;
|
|
||||||
const { reactionPickerRoot, isWide } = this.state;
|
const { reactionPickerRoot, isWide } = this.state;
|
||||||
const hasReactions = reactions && reactions.length > 0;
|
|
||||||
|
|
||||||
const multipleAttachments = attachments && attachments.length > 1;
|
const multipleAttachments = attachments && attachments.length > 1;
|
||||||
const firstAttachment = attachments && attachments[0];
|
const firstAttachment = attachments && attachments[0];
|
||||||
|
@ -1093,8 +1097,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'module-message__buttons',
|
'module-message__buttons',
|
||||||
`module-message__buttons--${direction}`,
|
`module-message__buttons--${direction}`
|
||||||
hasReactions ? 'module-message__buttons--has-reactions' : null
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{ENABLE_REACTION_SEND ? reactButton : null}
|
{ENABLE_REACTION_SEND ? reactButton : null}
|
||||||
|
@ -1524,16 +1527,43 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
['length', ([{ timestamp }]) => timestamp],
|
['length', ([{ timestamp }]) => timestamp],
|
||||||
['desc', 'desc']
|
['desc', 'desc']
|
||||||
);
|
);
|
||||||
// Take the first two groups for rendering
|
// Take the first three groups for rendering
|
||||||
const toRender = take(ordered, 2).map(res => ({
|
const toRender = take(ordered, 3).map(res => ({
|
||||||
emoji: res[0].emoji,
|
emoji: res[0].emoji,
|
||||||
|
count: res.length,
|
||||||
isMe: res.some(re => Boolean(re.from.isMe)),
|
isMe: res.some(re => Boolean(re.from.isMe)),
|
||||||
}));
|
}));
|
||||||
|
const someNotRendered = ordered.length > 3;
|
||||||
|
// We only drop two here because the third emoji would be replaced by the
|
||||||
|
// more button
|
||||||
|
const maybeNotRendered = drop(ordered, 2);
|
||||||
|
const maybeNotRenderedTotal = maybeNotRendered.reduce(
|
||||||
|
(sum, res) => sum + res.length,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const notRenderedIsMe =
|
||||||
|
someNotRendered &&
|
||||||
|
maybeNotRendered.some(res => res.some(re => Boolean(re.from.isMe)));
|
||||||
|
|
||||||
const reactionHeight = 32;
|
const { reactionViewerRoot, containerWidth } = this.state;
|
||||||
const { reactionsHeight: height, reactionViewerRoot } = this.state;
|
|
||||||
|
|
||||||
const offset = clamp((height - reactionHeight) / toRender.length, 4, 28);
|
// Calculate the width of the reactions container
|
||||||
|
const reactionsWidth = toRender.reduce((sum, res, i, arr) => {
|
||||||
|
if (someNotRendered && i === arr.length - 1) {
|
||||||
|
return sum + 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.count > 1) {
|
||||||
|
return sum + 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum + 28;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const reactionsXAxisOffset = Math.max(
|
||||||
|
containerWidth - reactionsWidth - 6,
|
||||||
|
6
|
||||||
|
);
|
||||||
|
|
||||||
const popperPlacement = outgoing ? 'bottom-end' : 'bottom-start';
|
const popperPlacement = outgoing ? 'bottom-end' : 'bottom-start';
|
||||||
|
|
||||||
|
@ -1541,58 +1571,83 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
<Manager>
|
<Manager>
|
||||||
<Reference>
|
<Reference>
|
||||||
{({ ref: popperRef }) => (
|
{({ ref: popperRef }) => (
|
||||||
<Measure
|
<div
|
||||||
bounds={true}
|
ref={mergeRefs(this.reactionsContainerRef, popperRef)}
|
||||||
onResize={({ bounds = { height: 0 } }) => {
|
className={classNames(
|
||||||
this.setState({ reactionsHeight: bounds.height });
|
'module-message__reactions',
|
||||||
|
outgoing
|
||||||
|
? 'module-message__reactions--outgoing'
|
||||||
|
: 'module-message__reactions--incoming'
|
||||||
|
)}
|
||||||
|
style={{
|
||||||
|
[outgoing ? 'right' : 'left']: `${reactionsXAxisOffset}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ measureRef }) => (
|
{toRender.map((re, i) => {
|
||||||
<div
|
const isLast = i === toRender.length - 1;
|
||||||
ref={mergeRefs(
|
const isMore = isLast && someNotRendered;
|
||||||
this.reactionsContainerRef,
|
const isMoreWithMe = isMore && notRenderedIsMe;
|
||||||
measureRef,
|
|
||||||
popperRef
|
return (
|
||||||
)}
|
<button
|
||||||
className={classNames(
|
key={`${re.emoji}-${i}`}
|
||||||
'module-message__reactions',
|
className={classNames(
|
||||||
outgoing
|
'module-message__reactions__reaction',
|
||||||
? 'module-message__reactions--outgoing'
|
re.count > 1
|
||||||
: 'module-message__reactions--incoming'
|
? 'module-message__reactions__reaction--with-count'
|
||||||
)}
|
: null,
|
||||||
>
|
outgoing
|
||||||
{toRender.map((re, i) => (
|
? 'module-message__reactions__reaction--outgoing'
|
||||||
<button
|
: 'module-message__reactions__reaction--incoming',
|
||||||
key={`${re.emoji}-${i}`}
|
isMoreWithMe || (re.isMe && !isMoreWithMe)
|
||||||
className={classNames(
|
? 'module-message__reactions__reaction--is-me'
|
||||||
'module-message__reactions__reaction',
|
: null
|
||||||
outgoing
|
)}
|
||||||
? 'module-message__reactions__reaction--outgoing'
|
onClick={e => {
|
||||||
: 'module-message__reactions__reaction--incoming',
|
e.stopPropagation();
|
||||||
re.isMe
|
e.preventDefault();
|
||||||
? 'module-message__reactions__reaction--is-me'
|
this.toggleReactionViewer();
|
||||||
: null
|
}}
|
||||||
)}
|
onKeyDown={e => {
|
||||||
style={{
|
// Prevent enter key from opening stickers/attachments
|
||||||
top: `${i * offset}px`,
|
if (e.key === 'Enter') {
|
||||||
}}
|
|
||||||
onClick={e => {
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.toggleReactionViewer();
|
}
|
||||||
}}
|
}}
|
||||||
onKeyDown={e => {
|
>
|
||||||
// Prevent enter key from opening stickers/attachments
|
{isMore ? (
|
||||||
if (e.key === 'Enter') {
|
<span
|
||||||
e.stopPropagation();
|
className={classNames(
|
||||||
}
|
'module-message__reactions__reaction__count',
|
||||||
}}
|
'module-message__reactions__reaction__count--no-emoji',
|
||||||
>
|
isMoreWithMe
|
||||||
<Emoji size={18} emoji={re.emoji} />
|
? 'module-message__reactions__reaction__count--is-me'
|
||||||
</button>
|
: null
|
||||||
))}
|
)}
|
||||||
</div>
|
>
|
||||||
)}
|
+{maybeNotRenderedTotal}
|
||||||
</Measure>
|
</span>
|
||||||
|
) : (
|
||||||
|
<React.Fragment>
|
||||||
|
<Emoji size={16} emoji={re.emoji} />
|
||||||
|
{re.count > 1 ? (
|
||||||
|
<span
|
||||||
|
className={classNames(
|
||||||
|
'module-message__reactions__reaction__count',
|
||||||
|
re.isMe
|
||||||
|
? 'module-message__reactions__reaction__count--is-me'
|
||||||
|
: null
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{re.count}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Reference>
|
</Reference>
|
||||||
{reactionViewerRoot &&
|
{reactionViewerRoot &&
|
||||||
|
@ -1604,14 +1659,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
style={{
|
style={{
|
||||||
...style,
|
...style,
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
marginTop: -(height - reactionHeight * 0.75),
|
|
||||||
...(outgoing
|
|
||||||
? {
|
|
||||||
marginRight: reactionHeight * -0.375,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
marginLeft: reactionHeight * -0.375,
|
|
||||||
}),
|
|
||||||
}}
|
}}
|
||||||
reactions={reactions}
|
reactions={reactions}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
@ -1816,6 +1863,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
isTapToView,
|
isTapToView,
|
||||||
isTapToViewExpired,
|
isTapToViewExpired,
|
||||||
isTapToViewError,
|
isTapToViewError,
|
||||||
|
reactions,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { isSelected } = this.state;
|
const { isSelected } = this.state;
|
||||||
|
|
||||||
|
@ -1844,6 +1892,9 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
: null,
|
: null,
|
||||||
isTapToViewError
|
isTapToViewError
|
||||||
? 'module-message__container--with-tap-to-view-error'
|
? 'module-message__container--with-tap-to-view-error'
|
||||||
|
: null,
|
||||||
|
reactions && reactions.length > 0
|
||||||
|
? 'module-message__container--with-reactions'
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
const containerStyles = {
|
const containerStyles = {
|
||||||
|
@ -1851,11 +1902,24 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClassnames} style={containerStyles}>
|
<Measure
|
||||||
{this.renderAuthor()}
|
bounds={true}
|
||||||
{this.renderContents()}
|
onResize={({ bounds = { width: 0 } }) => {
|
||||||
{this.renderAvatar()}
|
this.setState({ containerWidth: bounds.width });
|
||||||
</div>
|
}}
|
||||||
|
>
|
||||||
|
{({ measureRef }) => (
|
||||||
|
<div
|
||||||
|
ref={measureRef}
|
||||||
|
className={containerClassnames}
|
||||||
|
style={containerStyles}
|
||||||
|
>
|
||||||
|
{this.renderAuthor()}
|
||||||
|
{this.renderContents()}
|
||||||
|
{this.renderAvatar()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Measure>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,20 @@ export type MessageType = {
|
||||||
pending: boolean;
|
pending: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
unread: boolean;
|
||||||
|
reactions?: Array<{
|
||||||
|
emoji: string;
|
||||||
|
timestamp: number;
|
||||||
|
from: {
|
||||||
|
id: string;
|
||||||
|
color?: string;
|
||||||
|
avatarPath?: string;
|
||||||
|
name?: string;
|
||||||
|
profileName?: string;
|
||||||
|
isMe?: boolean;
|
||||||
|
phoneNumber?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
// No need to go beyond this; unused at this stage, since this goes into
|
// No need to go beyond this; unused at this stage, since this goes into
|
||||||
// a reducer still in plain JavaScript and comes out well-formed
|
// a reducer still in plain JavaScript and comes out well-formed
|
||||||
|
@ -573,6 +587,14 @@ function hasMessageHeightChanged(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentReactions = message.reactions || [];
|
||||||
|
const lastReactions = previous.reactions || [];
|
||||||
|
const reactionsChanged =
|
||||||
|
(currentReactions.length === 0) !== (lastReactions.length === 0);
|
||||||
|
if (reactionsChanged) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9250,17 +9250,17 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/Message.tsx",
|
"path": "ts/components/conversation/Message.tsx",
|
||||||
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
|
"line": " public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();",
|
||||||
"lineNumber": 176,
|
"lineNumber": 177,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-01-21T23:01:37.636Z"
|
"updated": "2020-02-03T17:18:39.600Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/Message.tsx",
|
"path": "ts/components/conversation/Message.tsx",
|
||||||
"line": " > = React.createRef();",
|
"line": " > = React.createRef();",
|
||||||
"lineNumber": 180,
|
"lineNumber": 181,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-01-21T23:01:37.636Z"
|
"updated": "2020-02-03T17:18:39.600Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue