Modernize DeliveryIssueDialog, fix outline clipping in Modal
This commit is contained in:
parent
21ffb7c054
commit
bcb9d2d2f3
16 changed files with 154 additions and 127 deletions
|
@ -10091,17 +10091,6 @@ $contact-modal-padding: 18px;
|
|||
|
||||
// Module: Delivery Issue Dialog
|
||||
|
||||
.module-delivery-issue-dialog {
|
||||
// margin-left: auto;
|
||||
// margin-right: auto;
|
||||
|
||||
@include light-theme {
|
||||
background-color: $color-white;
|
||||
}
|
||||
@include dark-theme {
|
||||
background-color: $color-gray-95;
|
||||
}
|
||||
}
|
||||
.module-delivery-issue-dialog__image {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -10110,31 +10099,6 @@ $contact-modal-padding: 18px;
|
|||
margin-top: 10px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.module-delivery-issue-dialog__buttons {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
padding: 3px;
|
||||
}
|
||||
.module-delivery-issue-dialog__button {
|
||||
}
|
||||
|
||||
.module-delivery-issue-dialog__learn-more-button {
|
||||
@include button-reset;
|
||||
@include button-secondary;
|
||||
@include font-body-1-bold;
|
||||
|
||||
border-radius: 4px;
|
||||
padding: 7px 14px;
|
||||
}
|
||||
.module-delivery-issue-dialog__close-button {
|
||||
@include button-reset;
|
||||
@include button-primary;
|
||||
@include font-body-1-bold;
|
||||
|
||||
border-radius: 4px;
|
||||
padding: 7px 14px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
/* Third-party module: react-contextmenu*/
|
||||
|
||||
|
|
|
@ -78,13 +78,14 @@
|
|||
&__body {
|
||||
@include font-body-1;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&--has-header {
|
||||
.module-Modal__body {
|
||||
padding: 0 16px 16px 16px;
|
||||
border-top: 1px solid transparent;
|
||||
// If there's a header, just the body scrolls
|
||||
overflow: auto;
|
||||
|
||||
&--scrolled {
|
||||
@include light-theme {
|
||||
|
@ -100,6 +101,8 @@
|
|||
|
||||
&--no-header {
|
||||
padding: 16px;
|
||||
// If there's no header, the whole thing scrolls
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__button-footer {
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as React from 'react';
|
|||
import classNames from 'classnames';
|
||||
|
||||
import { Avatar, Props as AvatarProps } from './Avatar';
|
||||
import { useRestoreFocus } from '../util/hooks';
|
||||
import { useRestoreFocus } from '../util/hooks/useRestoreFocus';
|
||||
|
||||
import { LocalizerType } from '../types/Util';
|
||||
|
||||
|
|
|
@ -32,6 +32,18 @@ story.add('Bare bones, long', () => (
|
|||
</Modal>
|
||||
));
|
||||
|
||||
story.add('Bare bones, long, with button', () => (
|
||||
<Modal i18n={i18n}>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<Modal.ButtonFooter>
|
||||
<Button onClick={noop}>Okay</Button>
|
||||
</Modal.ButtonFooter>
|
||||
</Modal>
|
||||
));
|
||||
|
||||
story.add('Title, X button, body, and button footer', () => (
|
||||
<Modal i18n={i18n} title="Hello world" onClose={onClose} hasXButton>
|
||||
{LOREM_IPSUM}
|
||||
|
@ -69,6 +81,18 @@ story.add('Long body with title', () => (
|
|||
</Modal>
|
||||
));
|
||||
|
||||
story.add('Long body with title and button', () => (
|
||||
<Modal i18n={i18n} title="Hello world" onClose={onClose}>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<p>{LOREM_IPSUM}</p>
|
||||
<Modal.ButtonFooter>
|
||||
<Button onClick={noop}>Okay</Button>
|
||||
</Modal.ButtonFooter>
|
||||
</Modal>
|
||||
));
|
||||
|
||||
story.add('Long body with long title and X button', () => (
|
||||
<Modal
|
||||
i18n={i18n}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useRestoreFocus } from '../util/hooks';
|
||||
import { useRestoreFocus } from '../util/hooks/useRestoreFocus';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
|
||||
export type Props = {
|
||||
|
|
|
@ -6,7 +6,7 @@ import classNames from 'classnames';
|
|||
|
||||
import { Modal } from '../Modal';
|
||||
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button, ButtonSize, ButtonVariant } from '../Button';
|
||||
import { ConversationType } from '../../state/ducks/conversations';
|
||||
import { Modal } from '../Modal';
|
||||
import { Intl } from '../Intl';
|
||||
import { Emojify } from './Emojify';
|
||||
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
|
@ -32,7 +33,7 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
|||
|
||||
return (
|
||||
<Modal hasXButton={false} onClose={onClose} i18n={i18n}>
|
||||
<div className="module-delivery-issue-dialog">
|
||||
<section>
|
||||
<div className="module-delivery-issue-dialog__image">
|
||||
<img
|
||||
src="images/delivery-issue.svg"
|
||||
|
@ -53,24 +54,25 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
|||
i18n={i18n}
|
||||
/>
|
||||
</div>
|
||||
<div className="module-delivery-issue-dialog__buttons">
|
||||
<button
|
||||
type="button"
|
||||
onClick={learnMoreAboutDeliveryIssue}
|
||||
className="module-delivery-issue-dialog__learn-more-button"
|
||||
>
|
||||
{i18n('DeliveryIssue--learnMore')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
ref={focusRef}
|
||||
className="module-delivery-issue-dialog__close-button"
|
||||
>
|
||||
{i18n('Confirmation--confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<Modal.ButtonFooter>
|
||||
<Button
|
||||
onClick={learnMoreAboutDeliveryIssue}
|
||||
size={ButtonSize.Medium}
|
||||
variant={ButtonVariant.Secondary}
|
||||
>
|
||||
{i18n('DeliveryIssue--learnMore')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onClose}
|
||||
ref={focusRef}
|
||||
size={ButtonSize.Medium}
|
||||
variant={ButtonVariant.Primary}
|
||||
className="module-delivery-issue-dialog__close-button"
|
||||
>
|
||||
{i18n('Confirmation--confirm')}
|
||||
</Button>
|
||||
</Modal.ButtonFooter>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import classNames from 'classnames';
|
|||
import { Emoji } from '../emoji/Emoji';
|
||||
import { convertShortName } from '../emoji/lib';
|
||||
import { Props as EmojiPickerProps } from '../emoji/EmojiPicker';
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
export type RenderEmojiPickerProps = Pick<Props, 'onClose' | 'style'> &
|
||||
|
|
|
@ -7,7 +7,7 @@ import classNames from 'classnames';
|
|||
import { ContactName } from './ContactName';
|
||||
import { Avatar, Props as AvatarProps } from '../Avatar';
|
||||
import { Emoji } from '../emoji/Emoji';
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
import { ConversationType } from '../../state/ducks/conversations';
|
||||
import { emojiToData, EmojiData } from '../emoji/lib';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
import { StickerPackType, StickerType } from '../../state/ducks/stickers';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { ConfirmationDialog } from '../ConfirmationDialog';
|
|||
import { LocalizerType } from '../../types/Util';
|
||||
import { StickerPackType } from '../../state/ducks/stickers';
|
||||
import { Spinner } from '../Spinner';
|
||||
import { useRestoreFocus } from '../../util/hooks';
|
||||
import { useRestoreFocus } from '../../util/hooks/useRestoreFocus';
|
||||
|
||||
export type OwnProps = {
|
||||
readonly onClose: () => unknown;
|
||||
|
|
|
@ -1060,6 +1060,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
if (isIncoming(this.attributes)) {
|
||||
return this.get('source');
|
||||
}
|
||||
if (!isOutgoing(this.attributes)) {
|
||||
window.log.warn(
|
||||
'Message.getSource: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return this.OUR_NUMBER;
|
||||
}
|
||||
|
@ -1070,6 +1075,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
if (isIncoming(this.attributes)) {
|
||||
return sourceDevice;
|
||||
}
|
||||
if (!isOutgoing(this.attributes)) {
|
||||
window.log.warn(
|
||||
'Message.getSourceDevice: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return sourceDevice || window.textsecure.storage.user.getDeviceId();
|
||||
}
|
||||
|
@ -1078,6 +1088,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
if (isIncoming(this.attributes)) {
|
||||
return this.get('sourceUuid');
|
||||
}
|
||||
if (!isOutgoing(this.attributes)) {
|
||||
window.log.warn(
|
||||
'Message.getSourceUuid: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return this.OUR_UUID;
|
||||
}
|
||||
|
|
|
@ -242,6 +242,11 @@ export function getSource(
|
|||
if (isIncoming(message)) {
|
||||
return message.source;
|
||||
}
|
||||
if (!isOutgoing(message)) {
|
||||
window.log.warn(
|
||||
'message.getSource: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return ourNumber;
|
||||
}
|
||||
|
@ -255,6 +260,11 @@ export function getSourceDevice(
|
|||
if (isIncoming(message)) {
|
||||
return sourceDevice;
|
||||
}
|
||||
if (!isOutgoing(message)) {
|
||||
window.log.warn(
|
||||
'message.getSourceDevice: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return sourceDevice || ourDeviceId;
|
||||
}
|
||||
|
@ -266,6 +276,11 @@ export function getSourceUuid(
|
|||
if (isIncoming(message)) {
|
||||
return message.sourceUuid;
|
||||
}
|
||||
if (!isOutgoing(message)) {
|
||||
window.log.warn(
|
||||
'message.getSourceUuid: Called for non-incoming/non-outoing message'
|
||||
);
|
||||
}
|
||||
|
||||
return ourUuid;
|
||||
}
|
||||
|
|
|
@ -13,49 +13,6 @@ export function usePrevious<T>(initialValue: T, currentValue: T): T {
|
|||
return result;
|
||||
}
|
||||
|
||||
type CallbackType = (toFocus: HTMLElement | null | undefined) => void;
|
||||
|
||||
// Restore focus on teardown
|
||||
export const useRestoreFocus = (): Array<CallbackType> => {
|
||||
const toFocusRef = React.useRef<HTMLElement | null>(null);
|
||||
const lastFocusedRef = React.useRef<HTMLElement | null>(null);
|
||||
|
||||
// We need to use a callback here because refs aren't necessarily populated on first
|
||||
// render. For example, ModalHost makes a top-level parent div first, and then renders
|
||||
// into it. And the children you pass it don't have access to that root div.
|
||||
const setFocusRef = React.useCallback(
|
||||
(toFocus: HTMLElement | null | undefined) => {
|
||||
if (!toFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only want to do this once.
|
||||
if (toFocusRef.current) {
|
||||
return;
|
||||
}
|
||||
toFocusRef.current = toFocus;
|
||||
|
||||
// Remember last-focused element, focus this new target element.
|
||||
lastFocusedRef.current = document.activeElement as HTMLElement;
|
||||
toFocus.focus();
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
// On unmount, returned focus to element focused before we set the focus
|
||||
setTimeout(() => {
|
||||
if (lastFocusedRef.current && lastFocusedRef.current.focus) {
|
||||
lastFocusedRef.current.focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [setFocusRef];
|
||||
};
|
||||
|
||||
export const useBoundActions = <T extends ActionCreatorsMapObject>(
|
||||
actions: T
|
||||
): T => {
|
47
ts/util/hooks/useRestoreFocus.ts
Normal file
47
ts/util/hooks/useRestoreFocus.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
type CallbackType = (toFocus: HTMLElement | null | undefined) => void;
|
||||
|
||||
// Restore focus on teardown
|
||||
export const useRestoreFocus = (): Array<CallbackType> => {
|
||||
const toFocusRef = React.useRef<HTMLElement | null>(null);
|
||||
const lastFocusedRef = React.useRef<HTMLElement | null>(null);
|
||||
|
||||
// We need to use a callback here because refs aren't necessarily populated on first
|
||||
// render. For example, ModalHost makes a top-level parent div first, and then renders
|
||||
// into it. And the children you pass it don't have access to that root div.
|
||||
const setFocusRef = React.useCallback(
|
||||
(toFocus: HTMLElement | null | undefined) => {
|
||||
if (!toFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only want to do this once.
|
||||
if (toFocusRef.current) {
|
||||
return;
|
||||
}
|
||||
toFocusRef.current = toFocus;
|
||||
|
||||
// Remember last-focused element, focus this new target element.
|
||||
lastFocusedRef.current = document.activeElement as HTMLElement;
|
||||
toFocus.focus();
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
// On unmount, returned focus to element focused before we set the focus
|
||||
setTimeout(() => {
|
||||
if (lastFocusedRef.current && lastFocusedRef.current.focus) {
|
||||
lastFocusedRef.current.focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [setFocusRef];
|
||||
};
|
|
@ -14398,7 +14398,7 @@
|
|||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.js",
|
||||
"path": "ts/util/hooks/index.js",
|
||||
"line": " const unobserveRef = React.useRef(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-01-08T15:46:32.143Z",
|
||||
|
@ -14406,7 +14406,7 @@
|
|||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.js",
|
||||
"path": "ts/util/hooks/index.js",
|
||||
"line": " const previousValueRef = React.useRef(initialValue);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-03-18T21:41:28.361Z",
|
||||
|
@ -14414,7 +14414,21 @@
|
|||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.js",
|
||||
"path": "ts/util/hooks/index.ts",
|
||||
"line": " const previousValueRef = React.useRef<T>(initialValue);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks/index.ts",
|
||||
"line": " const unobserveRef = React.useRef<(() => unknown) | null>(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks/useRestoreFocus.js",
|
||||
"line": " const toFocusRef = React.useRef(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T01:08:01.309Z",
|
||||
|
@ -14422,7 +14436,7 @@
|
|||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.js",
|
||||
"path": "ts/util/hooks/useRestoreFocus.js",
|
||||
"line": " const lastFocusedRef = React.useRef(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T01:08:01.309Z",
|
||||
|
@ -14430,30 +14444,16 @@
|
|||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.ts",
|
||||
"line": " const previousValueRef = React.useRef<T>(initialValue);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.ts",
|
||||
"path": "ts/util/hooks/useRestoreFocus.ts",
|
||||
"line": " const toFocusRef = React.useRef<HTMLElement | null>(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.ts",
|
||||
"path": "ts/util/hooks/useRestoreFocus.ts",
|
||||
"line": " const lastFocusedRef = React.useRef<HTMLElement | null>(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
},
|
||||
{
|
||||
"rule": "React-useRef",
|
||||
"path": "ts/util/hooks.ts",
|
||||
"line": " const unobserveRef = React.useRef<(() => unknown) | null>(null);",
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-07-30T16:57:33.618Z"
|
||||
}
|
||||
]
|
Loading…
Add table
Reference in a new issue