mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-28 12:23:31 +01:00
Keyboard/mouse mode and keyboard support bugfixes
This commit is contained in:
committed by
Ken Powers
parent
ed55006f20
commit
2a0a73cfc1
@@ -22,7 +22,7 @@ const contact = {
|
||||
onSendMessage: () => console.log('onSendMessage'),
|
||||
signalAccount: '+12025550000',
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -92,7 +92,7 @@ const contact = {
|
||||
onSendMessage: () => console.log('onSendMessage'),
|
||||
signalAccount: '+12025550000',
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -137,7 +137,7 @@ const contact = {
|
||||
},
|
||||
},
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -182,7 +182,7 @@ const contact = {
|
||||
},
|
||||
signalAccount: '+12025550000',
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -244,7 +244,7 @@ const contact = {
|
||||
},
|
||||
},
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -309,7 +309,7 @@ const contact = {
|
||||
},
|
||||
},
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -377,7 +377,7 @@ const contact = {
|
||||
},
|
||||
signalAccount: '+12025551000',
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -439,7 +439,7 @@ const contact = {
|
||||
},
|
||||
],
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -491,7 +491,7 @@ const contact = {
|
||||
|
||||
```jsx
|
||||
const contact = {};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -575,7 +575,7 @@ const contactWithoutAccount = {
|
||||
},
|
||||
},
|
||||
};
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
text="I want to introduce you to Someone..."
|
||||
|
||||
@@ -38,6 +38,7 @@ export class EmbeddedContact extends React.Component<Props> {
|
||||
<button
|
||||
className={classNames(
|
||||
'module-embedded-contact',
|
||||
`module-embedded-contact--${direction}`,
|
||||
withContentAbove
|
||||
? 'module-embedded-contact--with-content-above'
|
||||
: null,
|
||||
|
||||
@@ -4,7 +4,7 @@ export type PropsType = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
isSelected: boolean;
|
||||
selectMessage: (messageId: string, conversationId: string) => unknown;
|
||||
selectMessage?: (messageId: string, conversationId: string) => unknown;
|
||||
};
|
||||
|
||||
export class InlineNotificationWrapper extends React.Component<PropsType> {
|
||||
@@ -18,10 +18,19 @@ export class InlineNotificationWrapper extends React.Component<PropsType> {
|
||||
}
|
||||
};
|
||||
|
||||
public handleFocus = () => {
|
||||
// @ts-ignore
|
||||
if (window.getInteractionMode() === 'keyboard') {
|
||||
this.setSelected();
|
||||
}
|
||||
};
|
||||
|
||||
public setSelected = () => {
|
||||
const { id, conversationId, selectMessage } = this.props;
|
||||
|
||||
selectMessage(id, conversationId);
|
||||
if (selectMessage) {
|
||||
selectMessage(id, conversationId);
|
||||
}
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
@@ -45,7 +54,7 @@ export class InlineNotificationWrapper extends React.Component<PropsType> {
|
||||
className="module-inline-notification-wrapper"
|
||||
tabIndex={0}
|
||||
ref={this.focusRef}
|
||||
onFocus={this.setSelected}
|
||||
onFocus={this.handleFocus}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Note that timestamp and status can be hidden with the `collapseMetadata` boolean property.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -148,7 +148,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
### Status
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="outgoing"
|
||||
@@ -323,7 +323,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
### All colors
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -450,7 +450,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
### Long data
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="purple"
|
||||
@@ -515,7 +515,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
### Pending long message download
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="purple"
|
||||
@@ -553,7 +553,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
#### Image with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="blue"
|
||||
@@ -645,7 +645,7 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean
|
||||
First, showing the metadata overlay on dark and light images, then a message with `collapseMetadata` set.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -765,7 +765,7 @@ First, showing the metadata overlay on dark and light images, then a message wit
|
||||
Stickers have no background, but they have all the standard message bubble features.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -912,7 +912,7 @@ Stickers have no background, but they have all the standard message bubble featu
|
||||
First set is in a 1:1 conversation, second set is in a group.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1002,7 +1002,7 @@ First set is in a 1:1 conversation, second set is in a group.
|
||||
A sticker with no attachments (what our selectors produce for a pending sticker) is not displayed at all.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1062,7 +1062,7 @@ A sticker with no attachments (what our selectors produce for a pending sticker)
|
||||
#### Multiple images
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1244,7 +1244,7 @@ A sticker with no attachments (what our selectors produce for a pending sticker)
|
||||
#### Multiple images with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1433,7 +1433,7 @@ A sticker with no attachments (what our selectors produce for a pending sticker)
|
||||
Note that the delivered indicator is always Signal Blue, not the conversation color.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="outgoing"
|
||||
@@ -1512,7 +1512,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Pending images
|
||||
|
||||
```
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1617,7 +1617,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image with portrait aspect ratio
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="purple"
|
||||
@@ -1695,7 +1695,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image with portrait aspect ratio and caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1819,7 +1819,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image with landscape aspect ratio
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1897,7 +1897,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image with landscape aspect ratio and caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -1979,7 +1979,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Video with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2073,7 +2073,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Video
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2170,7 +2170,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Missing images and videos
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2349,7 +2349,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Broken source URL images and videos
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2441,7 +2441,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image/video which is too big
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2532,7 +2532,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Image/video missing height/width
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2619,7 +2619,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Audio with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2693,7 +2693,7 @@ Note that the delivered indicator is always Signal Blue, not the conversation co
|
||||
#### Audio
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2767,7 +2767,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
#### Other file type with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2906,7 +2906,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
#### Other file type
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -2984,7 +2984,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
#### Other file type pending
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3062,7 +3062,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
#### Dangerous file type
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3108,7 +3108,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
#### Link previews, full-size image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3219,7 +3219,7 @@ Voice notes are not shown any differently from audio attachments.
|
||||
Sticker link previews are forced to use the small link preview form, no matter the image size.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3273,7 +3273,7 @@ Sticker link previews are forced to use the small link preview form, no matter t
|
||||
#### Link previews, small image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3384,7 +3384,7 @@ Sticker link previews are forced to use the small link preview form, no matter t
|
||||
#### Link previews with pending image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3481,7 +3481,7 @@ Sticker link previews are forced to use the small link preview form, no matter t
|
||||
#### Link previews, no image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
authorColor="green"
|
||||
@@ -3568,7 +3568,7 @@ Sticker link previews are forced to use the small link preview form, no matter t
|
||||
### Tap to view
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -4004,7 +4004,7 @@ Sticker link previews are forced to use the small link preview form, no matter t
|
||||
Note that the author avatar goes away if `collapseMetadata` is set.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
|
||||
@@ -40,6 +40,7 @@ interface Trigger {
|
||||
// Same as MIN_WIDTH in ImageGrid.tsx
|
||||
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
|
||||
const STICKER_SIZE = 128;
|
||||
const SELECTED_TIMEOUT = 1000;
|
||||
|
||||
interface LinkPreviewType {
|
||||
title: string;
|
||||
@@ -56,6 +57,8 @@ export type PropsData = {
|
||||
textPending?: boolean;
|
||||
isSticker: boolean;
|
||||
isSelected: boolean;
|
||||
isSelectedCounter: number;
|
||||
interactionMode: 'mouse' | 'keyboard';
|
||||
direction: 'incoming' | 'outgoing';
|
||||
timestamp: number;
|
||||
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error';
|
||||
@@ -130,7 +133,7 @@ export type PropsActions = {
|
||||
sentAt: number;
|
||||
}
|
||||
) => void;
|
||||
selectMessage: (messageId: string, conversationId: string) => unknown;
|
||||
selectMessage?: (messageId: string, conversationId: string) => unknown;
|
||||
};
|
||||
|
||||
export type Props = PropsData & PropsHousekeeping & PropsActions;
|
||||
@@ -139,6 +142,9 @@ interface State {
|
||||
expiring: boolean;
|
||||
expired: boolean;
|
||||
imageBroken: boolean;
|
||||
|
||||
isSelected: boolean;
|
||||
prevSelectedCounter: number;
|
||||
}
|
||||
|
||||
const EXPIRATION_CHECK_MINIMUM = 2000;
|
||||
@@ -149,16 +155,46 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
public focusRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
public audioRef: React.RefObject<HTMLAudioElement> = React.createRef();
|
||||
|
||||
public state = {
|
||||
expiring: false,
|
||||
expired: false,
|
||||
imageBroken: false,
|
||||
};
|
||||
|
||||
public expirationCheckInterval: any;
|
||||
public expiredTimeout: any;
|
||||
public selectedTimeout: any;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
expiring: false,
|
||||
expired: false,
|
||||
imageBroken: false,
|
||||
|
||||
isSelected: props.isSelected,
|
||||
prevSelectedCounter: props.isSelectedCounter,
|
||||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps(props: Props, state: State): State {
|
||||
if (!props.isSelected) {
|
||||
return {
|
||||
...state,
|
||||
isSelected: false,
|
||||
prevSelectedCounter: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
props.isSelected &&
|
||||
props.isSelectedCounter !== state.prevSelectedCounter
|
||||
) {
|
||||
return {
|
||||
...state,
|
||||
isSelected: props.isSelected,
|
||||
prevSelectedCounter: props.isSelectedCounter,
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public captureMenuTrigger = (triggerRef: Trigger) => {
|
||||
this.menuTriggerRef = triggerRef;
|
||||
};
|
||||
@@ -180,10 +216,20 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
public handleFocus = () => {
|
||||
const { interactionMode } = this.props;
|
||||
|
||||
if (interactionMode === 'keyboard') {
|
||||
this.setSelected();
|
||||
}
|
||||
};
|
||||
|
||||
public setSelected = () => {
|
||||
const { id, conversationId, selectMessage } = this.props;
|
||||
|
||||
selectMessage(id, conversationId);
|
||||
if (selectMessage) {
|
||||
selectMessage(id, conversationId);
|
||||
}
|
||||
};
|
||||
|
||||
public setFocus = () => {
|
||||
@@ -195,6 +241,8 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
this.startSelectedTimer();
|
||||
|
||||
const { isSelected } = this.props;
|
||||
if (isSelected) {
|
||||
this.setFocus();
|
||||
@@ -228,6 +276,8 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Props) {
|
||||
this.startSelectedTimer();
|
||||
|
||||
if (!prevProps.isSelected && this.props.isSelected) {
|
||||
this.setFocus();
|
||||
}
|
||||
@@ -235,6 +285,23 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
this.checkExpired();
|
||||
}
|
||||
|
||||
public startSelectedTimer() {
|
||||
const { interactionMode } = this.props;
|
||||
const { isSelected } = this.state;
|
||||
|
||||
if (interactionMode === 'keyboard' || !isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selectedTimeout) {
|
||||
this.selectedTimeout = setTimeout(() => {
|
||||
this.selectedTimeout = undefined;
|
||||
this.setState({ isSelected: false });
|
||||
this.props.clearSelectedMessage();
|
||||
}, SELECTED_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
public checkExpired() {
|
||||
const now = Date.now();
|
||||
const { isExpired, expirationTimestamp, expirationLength } = this.props;
|
||||
@@ -598,6 +665,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
<button
|
||||
className={classNames(
|
||||
'module-message__link-preview',
|
||||
`module-message__link-preview--${direction}`,
|
||||
withContentAbove
|
||||
? 'module-message__link-preview--with-content-above'
|
||||
: null
|
||||
@@ -1389,12 +1457,12 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
const {
|
||||
authorColor,
|
||||
direction,
|
||||
isSelected,
|
||||
isSticker,
|
||||
isTapToView,
|
||||
isTapToViewExpired,
|
||||
isTapToViewError,
|
||||
} = this.props;
|
||||
const { isSelected } = this.state;
|
||||
|
||||
const isAttachmentPending = this.isAttachmentPending();
|
||||
|
||||
@@ -1447,7 +1515,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
isSticker,
|
||||
timestamp,
|
||||
} = this.props;
|
||||
const { expired, expiring, imageBroken } = this.state;
|
||||
const { expired, expiring, imageBroken, isSelected } = this.state;
|
||||
|
||||
// This id is what connects our triple-dot click with our associated pop-up menu.
|
||||
// It needs to be unique.
|
||||
@@ -1466,6 +1534,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
className={classNames(
|
||||
'module-message',
|
||||
`module-message--${direction}`,
|
||||
isSelected ? 'module-message--selected' : null,
|
||||
expiring ? 'module-message--expired' : null,
|
||||
conversationType === 'group' ? 'module-message--group' : null
|
||||
)}
|
||||
@@ -1475,7 +1544,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
role="button"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onClick={this.handleClick}
|
||||
onFocus={this.setSelected}
|
||||
onFocus={this.handleFocus}
|
||||
ref={this.focusRef}
|
||||
>
|
||||
{this.renderError(direction === 'incoming')}
|
||||
|
||||
@@ -35,12 +35,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export class MessageDetail extends React.Component<Props> {
|
||||
private readonly focusRef: React.RefObject<HTMLDivElement>;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.focusRef = React.createRef();
|
||||
}
|
||||
private readonly focusRef = React.createRef<HTMLDivElement>();
|
||||
|
||||
public componentDidMount() {
|
||||
// When this component is created, it's initially not part of the DOM, and then it's
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#### Plain text
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -41,7 +41,7 @@
|
||||
#### Name variations
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -112,7 +112,7 @@
|
||||
#### With emoji
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -148,7 +148,7 @@
|
||||
#### Replies to you or yourself
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -186,7 +186,12 @@
|
||||
#### In a group conversation
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} type="group" ios={util.ios}>
|
||||
<util.ConversationContext
|
||||
theme={util.theme}
|
||||
type="group"
|
||||
ios={util.ios}
|
||||
mode={util.mode}
|
||||
>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -231,7 +236,7 @@ Note: for incoming messages, quote color is taken from the parent message. For o
|
||||
messages the color is taken from the contact who wrote the quoted message.
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -610,7 +615,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Referenced message not found
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -687,7 +692,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Long names and context
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -729,7 +734,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### A lot of text in quotation
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -773,7 +778,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### A lot of text in quotation, with icon
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -825,7 +830,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### A lot of text in quotation, with image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -885,7 +890,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Image with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -937,7 +942,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -987,7 +992,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Image with no thumbnail
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1030,7 +1035,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Pending image download
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1073,7 +1078,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Video with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1125,7 +1130,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Video
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1175,7 +1180,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Video with no thumbnail
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1223,7 +1228,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Audio with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1267,7 +1272,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Audio
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1309,7 +1314,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Voice message
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1355,7 +1360,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Other file type with caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1438,7 +1443,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Other file type
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1482,7 +1487,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, image attachment, and caption
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1532,7 +1537,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, image attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1580,7 +1585,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, portrait image attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1628,7 +1633,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, video attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1686,7 +1691,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, audio attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1730,7 +1735,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Quote, file attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="module-message-container">
|
||||
<Message
|
||||
direction="incoming"
|
||||
@@ -1778,7 +1783,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### Plain text
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1796,7 +1801,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With an icon
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1818,7 +1823,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With an image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1843,7 +1848,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With attachment and no text
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
authorColor="blue"
|
||||
@@ -1867,7 +1872,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With generic attachment
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1889,7 +1894,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With a close button
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1908,7 +1913,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With a close button and icon
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
@@ -1931,7 +1936,7 @@ messages the color is taken from the contact who wrote the quoted message.
|
||||
#### With a close button and image
|
||||
|
||||
```jsx
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
||||
<util.ConversationContext theme={util.theme} ios={util.ios} mode={util.mode}>
|
||||
<div className="bottom-bar">
|
||||
<Quote
|
||||
text="How many ferrets do you have?"
|
||||
|
||||
@@ -99,20 +99,13 @@ export class Quote extends React.Component<Props, State> {
|
||||
|
||||
// This is important to ensure that using this quote to navigate to the referenced
|
||||
// message doesn't also trigger its parent message's keydown.
|
||||
if (onClick && (event.key === 'Enter' || event.key === 'Space')) {
|
||||
if (onClick && (event.key === 'Enter' || event.key === ' ')) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onClick();
|
||||
}
|
||||
};
|
||||
|
||||
// We prevent this from bubbling to prevent the focus flash around a message when
|
||||
// you click a quote.
|
||||
public handleMouseDown = (event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
public handleImageError = () => {
|
||||
// tslint:disable-next-line no-console
|
||||
console.log('Message: Image failed to load; failing over to placeholder');
|
||||
@@ -271,14 +264,20 @@ export class Quote extends React.Component<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// We don't want the overall click handler for the quote to fire, so we stop
|
||||
// propagation before handing control to the caller's callback.
|
||||
const onClick = (e: React.MouseEvent<{}>): void => {
|
||||
const clickHandler = (e: React.MouseEvent): void => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
onClose();
|
||||
};
|
||||
const keyDownHandler = (e: React.KeyboardEvent): void => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
// We need the container to give us the flexibility to implement the iOS design.
|
||||
return (
|
||||
@@ -288,7 +287,8 @@ export class Quote extends React.Component<Props, State> {
|
||||
// We can't be a button because the overall quote is a button; can't nest them
|
||||
role="button"
|
||||
className="module-quote__close-button"
|
||||
onClick={onClick}
|
||||
onKeyDown={keyDownHandler}
|
||||
onClick={clickHandler}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -383,7 +383,6 @@ export class Quote extends React.Component<Props, State> {
|
||||
<button
|
||||
onClick={onClick}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
className={classNames(
|
||||
'module-quote',
|
||||
isIncoming ? 'module-quote--incoming' : 'module-quote--outgoing',
|
||||
|
||||
@@ -55,6 +55,7 @@ const Tab = ({
|
||||
)}
|
||||
onClick={handleClick}
|
||||
role="tab"
|
||||
tabIndex={0}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
@@ -81,7 +82,7 @@ export class MediaGallery extends React.Component<Props, State> {
|
||||
const { selectedTab } = this.state;
|
||||
|
||||
return (
|
||||
<div className="module-media-gallery" tabIndex={0} ref={this.focusRef}>
|
||||
<div className="module-media-gallery" tabIndex={-1} ref={this.focusRef}>
|
||||
<div className="module-media-gallery__tab-container">
|
||||
<Tab
|
||||
label="Media"
|
||||
|
||||
Reference in New Issue
Block a user