Replaces ConfirmationModal with ConfirmationDialog
This commit is contained in:
parent
c9d74654bf
commit
e75bba1c52
25 changed files with 456 additions and 737 deletions
|
@ -29,7 +29,9 @@ const {
|
||||||
AttachmentList,
|
AttachmentList,
|
||||||
} = require('../../ts/components/conversation/AttachmentList');
|
} = require('../../ts/components/conversation/AttachmentList');
|
||||||
const { CaptionEditor } = require('../../ts/components/CaptionEditor');
|
const { CaptionEditor } = require('../../ts/components/CaptionEditor');
|
||||||
const { ConfirmationModal } = require('../../ts/components/ConfirmationModal');
|
const {
|
||||||
|
ConfirmationDialog,
|
||||||
|
} = require('../../ts/components/ConfirmationDialog');
|
||||||
const {
|
const {
|
||||||
ContactDetail,
|
ContactDetail,
|
||||||
} = require('../../ts/components/conversation/ContactDetail');
|
} = require('../../ts/components/conversation/ContactDetail');
|
||||||
|
@ -317,7 +319,7 @@ exports.setup = (options = {}) => {
|
||||||
const Components = {
|
const Components = {
|
||||||
AttachmentList,
|
AttachmentList,
|
||||||
CaptionEditor,
|
CaptionEditor,
|
||||||
ConfirmationModal,
|
ConfirmationDialog,
|
||||||
ContactDetail,
|
ContactDetail,
|
||||||
ContactListItem,
|
ContactListItem,
|
||||||
ContactModal,
|
ContactModal,
|
||||||
|
|
|
@ -9,7 +9,7 @@ window.ReactDOM = require('react-dom');
|
||||||
const { ipcRenderer, remote } = require('electron');
|
const { ipcRenderer, remote } = require('electron');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
const i18n = require('./js/modules/i18n');
|
const i18n = require('./js/modules/i18n');
|
||||||
const { ConfirmationModal } = require('./ts/components/ConfirmationModal');
|
const { ConfirmationDialog } = require('./ts/components/ConfirmationDialog');
|
||||||
const { makeGetter, makeSetter } = require('./preload_utils');
|
const { makeGetter, makeSetter } = require('./preload_utils');
|
||||||
const {
|
const {
|
||||||
getEnvironment,
|
getEnvironment,
|
||||||
|
@ -32,7 +32,7 @@ window.forCalling = config.forCalling === 'true';
|
||||||
window.forCamera = config.forCamera === 'true';
|
window.forCamera = config.forCamera === 'true';
|
||||||
window.Signal = {
|
window.Signal = {
|
||||||
Components: {
|
Components: {
|
||||||
ConfirmationModal,
|
ConfirmationDialog,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7673,278 +7673,6 @@ button.module-image__border-overlay:focus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module: SafetyNumberChangeDialog
|
|
||||||
|
|
||||||
.module-sfn-dialog__title {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-sfn-dialog__message {
|
|
||||||
@include font-body-2;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
color: $color-gray-60;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
color: $color-gray-25;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-sfn-dialog__contacts {
|
|
||||||
list-style-type: none;
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-sfn-dialog__contact {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
&--wrapper {
|
|
||||||
flex-grow: 1;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--name {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--number {
|
|
||||||
@include light-theme {
|
|
||||||
color: $color-gray-60;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
color: $color-gray-25;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--view {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
background: inherit;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 2px;
|
|
||||||
outline: none;
|
|
||||||
padding: 8px 14px;
|
|
||||||
|
|
||||||
@include keyboard-mode {
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0px 0px 0px 2px $ultramarine-ui-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
color: $ultramarine-ui-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
color: $ultramarine-ui-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-sfn-dialog__actions {
|
|
||||||
border-top: 1px solid $color-gray-05;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-left: -16px;
|
|
||||||
margin-right: -16px;
|
|
||||||
margin-top: -14px;
|
|
||||||
padding-left: 16px;
|
|
||||||
padding-right: 16px;
|
|
||||||
padding-top: 16px;
|
|
||||||
|
|
||||||
&--cancel {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
outline: none;
|
|
||||||
padding: 7px 14px;
|
|
||||||
|
|
||||||
@include mouse-mode {
|
|
||||||
&:hover {
|
|
||||||
background: $color-gray-15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include keyboard-mode {
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0px 0px 0px 2px $ultramarine-ui-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
background-color: $color-gray-05;
|
|
||||||
color: $ultramarine-ui-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
background-color: $color-gray-75;
|
|
||||||
color: $ultramarine-ui-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--confirm {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
background: $ultramarine-ui-light;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: $color-white;
|
|
||||||
margin-left: 12px;
|
|
||||||
outline: none;
|
|
||||||
padding: 7px 14px;
|
|
||||||
|
|
||||||
@include mouse-mode {
|
|
||||||
&:hover {
|
|
||||||
background: $ultramarine-brand-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include keyboard-mode {
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0px 0px 0px 2px $ultramarine-brand-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safety Number verification */
|
|
||||||
|
|
||||||
.module-safety-number {
|
|
||||||
&__icon {
|
|
||||||
height: 1.25em;
|
|
||||||
width: 1.25em;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__verification-label {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon--verified {
|
|
||||||
display: inline-block;
|
|
||||||
height: 1.25em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
width: 1.25em;
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
-webkit-mask: url('../images/icons/v2/check-24.svg') no-repeat center;
|
|
||||||
-webkit-mask-size: 100%;
|
|
||||||
background-color: #121212;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
-webkit-mask: url('../images/icons/v2/check-24.svg') no-repeat center;
|
|
||||||
-webkit-mask-size: 100%;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon--shield {
|
|
||||||
display: inline-block;
|
|
||||||
height: 1.25em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
width: 1.25em;
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
-webkit-mask: url('../images/icons/v2/safety-number-outline-24.svg')
|
|
||||||
no-repeat center;
|
|
||||||
-webkit-mask-size: 100%;
|
|
||||||
background-color: #121212;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
-webkit-mask: url('../images/icons/v2/safety-number-solid-24.svg')
|
|
||||||
no-repeat center;
|
|
||||||
-webkit-mask-size: 100%;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__verify-container {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__button--verify {
|
|
||||||
border-radius: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
|
||||||
outline: none;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__number {
|
|
||||||
background: #f6f6f6;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: solid 1px #dedede;
|
|
||||||
font-family: monospace;
|
|
||||||
margin: 20px auto 20px auto;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
width: 16em;
|
|
||||||
|
|
||||||
@include dark-theme {
|
|
||||||
background: #1b1b1b;
|
|
||||||
border: solid 1px #848484;
|
|
||||||
color: #f6f6f6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__verification-status {
|
|
||||||
margin: 30px 0 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__close-button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: inherit;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
@include keyboard-mode {
|
|
||||||
&:focus {
|
|
||||||
border: 1px solid $ultramarine-ui-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
|
|
||||||
@include light-theme {
|
|
||||||
@include color-svg('../images/icons/v2/x-24.svg', $color-gray-60);
|
|
||||||
}
|
|
||||||
@include dark-theme {
|
|
||||||
@include color-svg('../images/icons/v2/x-24.svg', $color-gray-05);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module: StickerPicker
|
// Module: StickerPicker
|
||||||
|
|
||||||
.module-sticker-picker {
|
.module-sticker-picker {
|
||||||
|
@ -8873,112 +8601,6 @@ button.module-image__border-overlay:focus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module: confirmation dialog
|
|
||||||
.module-confirmation-dialog {
|
|
||||||
&__overlay {
|
|
||||||
background: $color-black-alpha-40;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
// THIS Z-INDEX IS OVER NINE THOUSAND. OVER NINE THOUSAND?! THAT CAN'T BE!
|
|
||||||
z-index: 9001;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__container {
|
|
||||||
width: 360px;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
@include popper-shadow();
|
|
||||||
|
|
||||||
@include light-theme() {
|
|
||||||
background: $color-white;
|
|
||||||
color: $color-gray-90;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme() {
|
|
||||||
background: $color-gray-80;
|
|
||||||
color: $color-gray-05;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
@include font-body-1-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
@include font-body-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
margin-top: 22px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
&__button {
|
|
||||||
margin-left: 4px;
|
|
||||||
border-radius: 17px;
|
|
||||||
height: 34px;
|
|
||||||
padding: 5px 12px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
@include font-body-1-bold;
|
|
||||||
|
|
||||||
@include mouse-mode {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include light-theme() {
|
|
||||||
background: $color-white;
|
|
||||||
color: $color-gray-60;
|
|
||||||
border: 1px solid $color-gray-60;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme() {
|
|
||||||
background: $color-gray-75;
|
|
||||||
color: $color-gray-25;
|
|
||||||
border: 1px solid $color-gray-25;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--negative {
|
|
||||||
@include light-theme() {
|
|
||||||
border: none;
|
|
||||||
background: $color-accent-red;
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme() {
|
|
||||||
border: none;
|
|
||||||
background: $color-accent-red;
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--affirmative {
|
|
||||||
@include light-theme() {
|
|
||||||
border: none;
|
|
||||||
background: $color-accent-green;
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include dark-theme() {
|
|
||||||
border: none;
|
|
||||||
background: $color-accent-green;
|
|
||||||
color: $color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-left-pane-dialog {
|
.module-left-pane-dialog {
|
||||||
background: $color-accent-green;
|
background: $color-accent-green;
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
|
|
|
@ -88,5 +88,9 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.module-Button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
78
stylesheets/components/SafetyNumberChangeDialog.scss
Normal file
78
stylesheets/components/SafetyNumberChangeDialog.scss
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
.module-SafetyNumberChangeDialog {
|
||||||
|
&__message {
|
||||||
|
@include font-body-2;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contacts {
|
||||||
|
list-style-type: none;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
&--wrapper {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--name {
|
||||||
|
@include font-body-1-bold;
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--number {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--view {
|
||||||
|
@include font-body-1-bold;
|
||||||
|
background: inherit;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 2px;
|
||||||
|
outline: none;
|
||||||
|
padding: 8px 14px;
|
||||||
|
|
||||||
|
@include keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0px 0px 0px 2px $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $ultramarine-ui-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
stylesheets/components/SafetyNumberViewer.scss
Normal file
122
stylesheets/components/SafetyNumberViewer.scss
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
.module-SafetyNumberViewer {
|
||||||
|
&__icon {
|
||||||
|
height: 1.25em;
|
||||||
|
width: 1.25em;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__verification-label {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon--verified {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.25em;
|
||||||
|
margin-right: 4px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
width: 1.25em;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
-webkit-mask: url('../images/icons/v2/check-24.svg') no-repeat center;
|
||||||
|
-webkit-mask-size: 100%;
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
-webkit-mask: url('../images/icons/v2/check-24.svg') no-repeat center;
|
||||||
|
-webkit-mask-size: 100%;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon--shield {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.25em;
|
||||||
|
margin-right: 4px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
width: 1.25em;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
-webkit-mask: url('../images/icons/v2/safety-number-outline-24.svg')
|
||||||
|
no-repeat center;
|
||||||
|
-webkit-mask-size: 100%;
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
-webkit-mask: url('../images/icons/v2/safety-number-solid-24.svg')
|
||||||
|
no-repeat center;
|
||||||
|
-webkit-mask-size: 100%;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__verify-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button--verify {
|
||||||
|
border-radius: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
background: #f6f6f6;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: solid 1px #dedede;
|
||||||
|
font-family: monospace;
|
||||||
|
margin: 20px auto 20px auto;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 16em;
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
background: #1b1b1b;
|
||||||
|
border: solid 1px #848484;
|
||||||
|
color: #f6f6f6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__verification-status {
|
||||||
|
margin: 30px 0 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: inherit;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
@include keyboard-mode {
|
||||||
|
&:focus {
|
||||||
|
border: 1px solid $ultramarine-ui-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
@include color-svg('../images/icons/v2/x-24.svg', $color-gray-60);
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
@include color-svg('../images/icons/v2/x-24.svg', $color-gray-05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,5 +38,7 @@
|
||||||
@import './components/GroupTitleInput.scss';
|
@import './components/GroupTitleInput.scss';
|
||||||
@import './components/MessageAudio.scss';
|
@import './components/MessageAudio.scss';
|
||||||
@import './components/Modal.scss';
|
@import './components/Modal.scss';
|
||||||
|
@import './components/SafetyNumberChangeDialog.scss';
|
||||||
|
@import './components/SafetyNumberViewer.scss';
|
||||||
@import './components/SearchResultsLoadingFakeHeader.scss';
|
@import './components/SearchResultsLoadingFakeHeader.scss';
|
||||||
@import './components/SearchResultsLoadingFakeRow.scss';
|
@import './components/SearchResultsLoadingFakeRow.scss';
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ConfirmationModal } from './ConfirmationModal';
|
import { Modal } from './Modal';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import {
|
import {
|
||||||
AudioDevice,
|
AudioDevice,
|
||||||
|
@ -135,12 +135,7 @@ export const CallingDeviceSelection = ({
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<Modal i18n={i18n} theme={Theme.Dark} onClose={toggleSettings}>
|
||||||
actions={[]}
|
|
||||||
i18n={i18n}
|
|
||||||
theme={Theme.Dark}
|
|
||||||
onClose={toggleSettings}
|
|
||||||
>
|
|
||||||
<div className="module-calling-device-selection">
|
<div className="module-calling-device-selection">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -210,6 +205,6 @@ export const CallingDeviceSelection = ({
|
||||||
{renderAudioOptions(availableSpeakers, i18n, selectedSpeaker)}
|
{renderAudioOptions(availableSpeakers, i18n, selectedSpeaker)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmationModal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classNames from 'classnames';
|
import { Button, ButtonVariant } from './Button';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
import { Modal } from './Modal';
|
||||||
|
import { Theme } from '../util/theme';
|
||||||
|
|
||||||
export type ActionSpec = {
|
export type ActionSpec = {
|
||||||
text: string;
|
text: string;
|
||||||
|
@ -12,12 +14,14 @@ export type ActionSpec = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
readonly actions: Array<ActionSpec>;
|
readonly actions?: Array<ActionSpec>;
|
||||||
readonly cancelText?: string;
|
readonly cancelText?: string;
|
||||||
readonly children?: React.ReactNode;
|
readonly children?: React.ReactNode;
|
||||||
readonly i18n: LocalizerType;
|
readonly i18n: LocalizerType;
|
||||||
|
readonly onCancel?: () => unknown;
|
||||||
readonly onClose: () => unknown;
|
readonly onClose: () => unknown;
|
||||||
readonly title?: string | React.ReactNode;
|
readonly title?: string | React.ReactNode;
|
||||||
|
readonly theme?: Theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Props = OwnProps;
|
export type Props = OwnProps;
|
||||||
|
@ -28,85 +32,77 @@ function focusRef(el: HTMLElement | null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This should use <Modal>. See DESKTOP-1038.
|
function getButtonVariant(
|
||||||
export const ConfirmationDialog = React.memo(
|
buttonStyle?: 'affirmative' | 'negative'
|
||||||
({ i18n, onClose, cancelText, children, title, actions }: Props) => {
|
): ButtonVariant {
|
||||||
React.useEffect(() => {
|
if (buttonStyle === 'affirmative') {
|
||||||
const handler = ({ key }: KeyboardEvent) => {
|
return ButtonVariant.Primary;
|
||||||
if (key === 'Escape') {
|
}
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('keydown', handler);
|
|
||||||
|
|
||||||
return () => {
|
if (buttonStyle === 'negative') {
|
||||||
document.removeEventListener('keydown', handler);
|
return ButtonVariant.Destructive;
|
||||||
};
|
}
|
||||||
}, [onClose]);
|
|
||||||
|
return ButtonVariant.Secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ConfirmationDialog = React.memo(
|
||||||
|
({
|
||||||
|
actions = [],
|
||||||
|
cancelText,
|
||||||
|
children,
|
||||||
|
i18n,
|
||||||
|
onCancel,
|
||||||
|
onClose,
|
||||||
|
theme,
|
||||||
|
title,
|
||||||
|
}: Props) => {
|
||||||
|
const cancelAndClose = React.useCallback(() => {
|
||||||
|
if (onCancel) {
|
||||||
|
onCancel();
|
||||||
|
}
|
||||||
|
onClose();
|
||||||
|
}, [onCancel, onClose]);
|
||||||
|
|
||||||
const handleCancel = React.useCallback(
|
const handleCancel = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
onClose();
|
cancelAndClose();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onClose]
|
[cancelAndClose]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleAction = React.useCallback(
|
const hasActions = Boolean(actions.length);
|
||||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
if (e.currentTarget.dataset.action) {
|
|
||||||
const actionIndex = parseInt(e.currentTarget.dataset.action, 10);
|
|
||||||
const { action } = actions[actionIndex];
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
onClose();
|
|
||||||
},
|
|
||||||
[onClose, actions]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-confirmation-dialog__container">
|
<Modal i18n={i18n} onClose={cancelAndClose} title={title} theme={theme}>
|
||||||
{title ? (
|
{children}
|
||||||
<h1 className="module-confirmation-dialog__container__title">
|
<Modal.Footer>
|
||||||
{title}
|
<Button
|
||||||
</h1>
|
onClick={handleCancel}
|
||||||
) : null}
|
ref={focusRef}
|
||||||
<div className="module-confirmation-dialog__container__content">
|
variant={
|
||||||
{children}
|
hasActions ? ButtonVariant.Secondary : ButtonVariant.Primary
|
||||||
</div>
|
}
|
||||||
{actions.length > 0 && (
|
>
|
||||||
<div className="module-confirmation-dialog__container__buttons">
|
{cancelText || i18n('confirmation-dialog--Cancel')}
|
||||||
<button
|
</Button>
|
||||||
type="button"
|
{actions.map((action, i) => (
|
||||||
onClick={handleCancel}
|
<Button
|
||||||
ref={focusRef}
|
key={action.text}
|
||||||
className="module-confirmation-dialog__container__buttons__button"
|
onClick={() => {
|
||||||
|
action.action();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
data-action={i}
|
||||||
|
variant={getButtonVariant(action.style)}
|
||||||
>
|
>
|
||||||
{cancelText || i18n('confirmation-dialog--Cancel')}
|
{action.text}
|
||||||
</button>
|
</Button>
|
||||||
{actions.map((action, i) => (
|
))}
|
||||||
<button
|
</Modal.Footer>
|
||||||
type="button"
|
</Modal>
|
||||||
key={action.text}
|
|
||||||
onClick={handleAction}
|
|
||||||
data-action={i}
|
|
||||||
className={classNames(
|
|
||||||
'module-confirmation-dialog__container__buttons__button',
|
|
||||||
action.style === 'affirmative'
|
|
||||||
? 'module-confirmation-dialog__container__buttons__button--affirmative'
|
|
||||||
: null,
|
|
||||||
action.style === 'negative'
|
|
||||||
? 'module-confirmation-dialog__container__buttons__button--negative'
|
|
||||||
: null
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{action.text}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
// Copyright 2019-2020 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { createPortal } from 'react-dom';
|
|
||||||
import {
|
|
||||||
ConfirmationDialog,
|
|
||||||
Props as ConfirmationDialogProps,
|
|
||||||
} from './ConfirmationDialog';
|
|
||||||
import { LocalizerType } from '../types/Util';
|
|
||||||
import { Theme, themeClassName } from '../util/theme';
|
|
||||||
|
|
||||||
export type OwnProps = {
|
|
||||||
readonly i18n: LocalizerType;
|
|
||||||
readonly onClose: () => unknown;
|
|
||||||
readonly theme?: Theme;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Props = OwnProps & ConfirmationDialogProps;
|
|
||||||
|
|
||||||
export const ConfirmationModal = React.memo(
|
|
||||||
({ i18n, onClose, theme, children, ...rest }: Props) => {
|
|
||||||
const [root, setRoot] = React.useState<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
document.body.appendChild(div);
|
|
||||||
setRoot(div);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.body.removeChild(div);
|
|
||||||
setRoot(null);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const handler = (event: KeyboardEvent) => {
|
|
||||||
if (event.key === 'Escape') {
|
|
||||||
onClose();
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('keydown', handler);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('keydown', handler);
|
|
||||||
};
|
|
||||||
}, [onClose]);
|
|
||||||
|
|
||||||
const handleCancel = React.useCallback(
|
|
||||||
(e: React.MouseEvent) => {
|
|
||||||
if (e.target === e.currentTarget) {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeyCancel = React.useCallback(
|
|
||||||
(e: React.KeyboardEvent) => {
|
|
||||||
if (e.target === e.currentTarget && e.keyCode === 27) {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
return root
|
|
||||||
? createPortal(
|
|
||||||
<div
|
|
||||||
role="presentation"
|
|
||||||
className={classNames(
|
|
||||||
'module-confirmation-dialog__overlay',
|
|
||||||
theme ? themeClassName(theme) : undefined
|
|
||||||
)}
|
|
||||||
onClick={handleCancel}
|
|
||||||
onKeyUp={handleKeyCancel}
|
|
||||||
>
|
|
||||||
<ConfirmationDialog i18n={i18n} {...rest} onClose={onClose}>
|
|
||||||
{children}
|
|
||||||
</ConfirmationDialog>
|
|
||||||
</div>,
|
|
||||||
root
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -4,7 +4,8 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { ConfirmationModal } from './ConfirmationModal';
|
import { Modal } from './Modal';
|
||||||
|
import { Button, ButtonVariant } from './Button';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
buttonText?: string;
|
buttonText?: string;
|
||||||
|
@ -21,30 +22,29 @@ function focusRef(el: HTMLElement | null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This should use <Modal>. See DESKTOP-1038.
|
|
||||||
export const ErrorModal = (props: PropsType): JSX.Element => {
|
export const ErrorModal = (props: PropsType): JSX.Element => {
|
||||||
const { buttonText, description, i18n, onClose, title } = props;
|
const { buttonText, description, i18n, onClose, title } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<Modal
|
||||||
actions={[]}
|
|
||||||
title={title || i18n('ErrorModal--title')}
|
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
title={title || i18n('ErrorModal--title')}
|
||||||
>
|
>
|
||||||
<div className="module-error-modal__description">
|
<>
|
||||||
{description || i18n('ErrorModal--description')}
|
<div className="module-error-modal__description">
|
||||||
</div>
|
{description || i18n('ErrorModal--description')}
|
||||||
<div className="module-error-modal__button-container">
|
</div>
|
||||||
<button
|
<Modal.Footer>
|
||||||
type="button"
|
<Button
|
||||||
className="module-confirmation-dialog__container__buttons__button"
|
onClick={onClose}
|
||||||
onClick={onClose}
|
ref={focusRef}
|
||||||
ref={focusRef}
|
variant={ButtonVariant.Secondary}
|
||||||
>
|
>
|
||||||
{buttonText || i18n('Confirmation--confirm')}
|
{buttonText || i18n('Confirmation--confirm')}
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</Modal.Footer>
|
||||||
</ConfirmationModal>
|
</>
|
||||||
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { CallBackgroundBlur } from './CallBackgroundBlur';
|
import { CallBackgroundBlur } from './CallBackgroundBlur';
|
||||||
import { Avatar, AvatarSize } from './Avatar';
|
import { Avatar, AvatarSize } from './Avatar';
|
||||||
import { ConfirmationModal } from './ConfirmationModal';
|
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||||
import { Intl } from './Intl';
|
import { Intl } from './Intl';
|
||||||
import { ContactName } from './conversation/ContactName';
|
import { ContactName } from './conversation/ContactName';
|
||||||
import { useIntersectionObserver } from '../util/hooks';
|
import { useIntersectionObserver } from '../util/hooks';
|
||||||
|
@ -200,7 +200,8 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showBlockInfo && (
|
{showBlockInfo && (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
|
cancelText={i18n('ok')}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setShowBlockInfo(false);
|
setShowBlockInfo(false);
|
||||||
|
@ -221,18 +222,9 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
actions={[
|
|
||||||
{
|
|
||||||
text: i18n('ok'),
|
|
||||||
action: () => {
|
|
||||||
setShowBlockInfo(false);
|
|
||||||
},
|
|
||||||
style: 'affirmative',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
{i18n('calling__block-info')}
|
{i18n('calling__block-info')}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { noop } from 'lodash';
|
||||||
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { ModalHost } from './ModalHost';
|
import { ModalHost } from './ModalHost';
|
||||||
|
import { Theme } from '../util/theme';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
@ -14,6 +15,7 @@ type PropsType = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
|
theme?: Theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Modal({
|
export function Modal({
|
||||||
|
@ -22,13 +24,14 @@ export function Modal({
|
||||||
i18n,
|
i18n,
|
||||||
onClose = noop,
|
onClose = noop,
|
||||||
title,
|
title,
|
||||||
|
theme,
|
||||||
}: Readonly<PropsType>): ReactElement {
|
}: Readonly<PropsType>): ReactElement {
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
|
||||||
const hasHeader = Boolean(hasXButton || title);
|
const hasHeader = Boolean(hasXButton || title);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalHost onClose={onClose}>
|
<ModalHost onClose={onClose} theme={theme}>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'module-Modal',
|
'module-Modal',
|
||||||
|
|
|
@ -1,65 +1,73 @@
|
||||||
// Copyright 2019-2020 Signal Messenger, LLC
|
// Copyright 2019-2020 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import * as React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { Theme, themeClassName } from '../util/theme';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
readonly onClose: () => unknown;
|
readonly onClose: () => unknown;
|
||||||
readonly children: React.ReactElement;
|
readonly children: React.ReactElement;
|
||||||
|
readonly theme?: Theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModalHost = React.memo(({ onClose, children }: PropsType) => {
|
export const ModalHost = React.memo(
|
||||||
const [root, setRoot] = React.useState<HTMLElement | null>(null);
|
({ onClose, children, theme }: PropsType) => {
|
||||||
|
const [root, setRoot] = React.useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
setRoot(div);
|
setRoot(div);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
setRoot(null);
|
setRoot(null);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (event: KeyboardEvent) => {
|
const handler = (event: KeyboardEvent) => {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
onClose();
|
onClose();
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener('keydown', handler);
|
document.addEventListener('keydown', handler);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
}, [onClose]);
|
}, [onClose]);
|
||||||
|
|
||||||
// This makes it easier to write dialogs to be hosted here; they won't have to worry
|
// This makes it easier to write dialogs to be hosted here; they won't have to worry
|
||||||
// as much about preventing propagation of mouse events.
|
// as much about preventing propagation of mouse events.
|
||||||
const handleCancel = React.useCallback(
|
const handleCancel = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onClose]
|
[onClose]
|
||||||
);
|
);
|
||||||
|
|
||||||
return root
|
return root
|
||||||
? createPortal(
|
? createPortal(
|
||||||
<div
|
<div
|
||||||
role="presentation"
|
role="presentation"
|
||||||
className="module-modal-host__overlay"
|
className={classNames(
|
||||||
onClick={handleCancel}
|
'module-modal-host__overlay',
|
||||||
>
|
theme ? themeClassName(theme) : undefined
|
||||||
{children}
|
)}
|
||||||
</div>,
|
onClick={handleCancel}
|
||||||
root
|
>
|
||||||
)
|
{children}
|
||||||
: null;
|
</div>,
|
||||||
});
|
root
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import enMessages from '../../_locales/en/messages.json';
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const contactWithAllData = {
|
const contactWithAllData = {
|
||||||
|
id: 'abc',
|
||||||
avatarPath: undefined,
|
avatarPath: undefined,
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
profileName: '-*Smartest Dude*-',
|
profileName: '-*Smartest Dude*-',
|
||||||
|
@ -22,6 +23,7 @@ const contactWithAllData = {
|
||||||
} as ConversationType;
|
} as ConversationType;
|
||||||
|
|
||||||
const contactWithJustProfile = {
|
const contactWithJustProfile = {
|
||||||
|
id: 'def',
|
||||||
avatarPath: undefined,
|
avatarPath: undefined,
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
title: '-*Smartest Dude*-',
|
title: '-*Smartest Dude*-',
|
||||||
|
@ -31,6 +33,7 @@ const contactWithJustProfile = {
|
||||||
} as ConversationType;
|
} as ConversationType;
|
||||||
|
|
||||||
const contactWithJustNumber = {
|
const contactWithJustNumber = {
|
||||||
|
id: 'xyz',
|
||||||
avatarPath: undefined,
|
avatarPath: undefined,
|
||||||
color: 'signal-blue',
|
color: 'signal-blue',
|
||||||
profileName: undefined,
|
profileName: undefined,
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { noop } from 'lodash';
|
||||||
|
|
||||||
import { Avatar } from './Avatar';
|
import { Avatar } from './Avatar';
|
||||||
import { ConfirmationModal } from './ConfirmationModal';
|
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||||
import { InContactsIcon } from './InContactsIcon';
|
import { InContactsIcon } from './InContactsIcon';
|
||||||
|
import { Modal } from './Modal';
|
||||||
|
|
||||||
import { ConversationType } from '../state/ducks/conversations';
|
import { ConversationType } from '../state/ducks/conversations';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
@ -24,18 +26,17 @@ export type Props = {
|
||||||
readonly renderSafetyNumber: (props: SafetyNumberProps) => JSX.Element;
|
readonly renderSafetyNumber: (props: SafetyNumberProps) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SafetyDialogContentProps = Props & {
|
export const SafetyNumberChangeDialog = ({
|
||||||
readonly onView: (contact: ConversationType) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SafetyDialogContents = ({
|
|
||||||
confirmText,
|
confirmText,
|
||||||
contacts,
|
contacts,
|
||||||
i18n,
|
i18n,
|
||||||
onCancel,
|
onCancel,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
onView,
|
renderSafetyNumber,
|
||||||
}: SafetyDialogContentProps): JSX.Element => {
|
}: Props): JSX.Element => {
|
||||||
|
const [selectedContact, setSelectedContact] = React.useState<
|
||||||
|
ConversationType | undefined
|
||||||
|
>(undefined);
|
||||||
const cancelButtonRef = React.createRef<HTMLButtonElement>();
|
const cancelButtonRef = React.createRef<HTMLButtonElement>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -44,20 +45,46 @@ const SafetyDialogContents = ({
|
||||||
}
|
}
|
||||||
}, [cancelButtonRef, contacts]);
|
}, [cancelButtonRef, contacts]);
|
||||||
|
|
||||||
|
const onClose = selectedContact
|
||||||
|
? () => {
|
||||||
|
setSelectedContact(undefined);
|
||||||
|
}
|
||||||
|
: onCancel;
|
||||||
|
|
||||||
|
if (selectedContact) {
|
||||||
|
return (
|
||||||
|
<Modal i18n={i18n}>
|
||||||
|
{renderSafetyNumber({ contactID: selectedContact.id, onClose })}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ConfirmationDialog
|
||||||
<h1 className="module-sfn-dialog__title">
|
actions={[
|
||||||
{i18n('safetyNumberChanges')}
|
{
|
||||||
</h1>
|
action: onConfirm,
|
||||||
<div className="module-sfn-dialog__message">
|
text: confirmText || i18n('sendMessageToContact'),
|
||||||
|
style: 'affirmative',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
i18n={i18n}
|
||||||
|
onCancel={onClose}
|
||||||
|
onClose={noop}
|
||||||
|
title={i18n('safetyNumberChanges')}
|
||||||
|
>
|
||||||
|
<div className="module-SafetyNumberChangeDialog__message">
|
||||||
{i18n('changedVerificationWarning')}
|
{i18n('changedVerificationWarning')}
|
||||||
</div>
|
</div>
|
||||||
<ul className="module-sfn-dialog__contacts">
|
<ul className="module-SafetyNumberChangeDialog__contacts">
|
||||||
{contacts.map((contact: ConversationType) => {
|
{contacts.map((contact: ConversationType) => {
|
||||||
const shouldShowNumber = Boolean(contact.name || contact.profileName);
|
const shouldShowNumber = Boolean(contact.name || contact.profileName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="module-sfn-dialog__contact" key={contact.id}>
|
<li
|
||||||
|
className="module-SafetyNumberChangeDialog__contact"
|
||||||
|
key={contact.id}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarPath={contact.avatarPath}
|
avatarPath={contact.avatarPath}
|
||||||
color={contact.color}
|
color={contact.color}
|
||||||
|
@ -69,8 +96,8 @@ const SafetyDialogContents = ({
|
||||||
title={contact.title}
|
title={contact.title}
|
||||||
size={52}
|
size={52}
|
||||||
/>
|
/>
|
||||||
<div className="module-sfn-dialog__contact--wrapper">
|
<div className="module-SafetyNumberChangeDialog__contact--wrapper">
|
||||||
<div className="module-sfn-dialog__contact--name">
|
<div className="module-SafetyNumberChangeDialog__contact--name">
|
||||||
{contact.title}
|
{contact.title}
|
||||||
{contact.name ? (
|
{contact.name ? (
|
||||||
<span>
|
<span>
|
||||||
|
@ -80,15 +107,15 @@ const SafetyDialogContents = ({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{shouldShowNumber ? (
|
{shouldShowNumber ? (
|
||||||
<div className="module-sfn-dialog__contact--number">
|
<div className="module-SafetyNumberChangeDialog__contact--number">
|
||||||
{contact.phoneNumber}
|
{contact.phoneNumber}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="module-sfn-dialog__contact--view"
|
className="module-SafetyNumberChangeDialog__contact--view"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onView(contact);
|
setSelectedContact(contact);
|
||||||
}}
|
}}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -99,52 +126,6 @@ const SafetyDialogContents = ({
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="module-sfn-dialog__actions">
|
</ConfirmationDialog>
|
||||||
<button
|
|
||||||
className="module-sfn-dialog__actions--cancel"
|
|
||||||
onClick={onCancel}
|
|
||||||
ref={cancelButtonRef}
|
|
||||||
tabIndex={0}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{i18n('cancel')}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="module-sfn-dialog__actions--confirm"
|
|
||||||
onClick={onConfirm}
|
|
||||||
tabIndex={0}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{confirmText || i18n('sendMessageToContact')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SafetyNumberChangeDialog = (props: Props): JSX.Element => {
|
|
||||||
const { i18n, onCancel, renderSafetyNumber } = props;
|
|
||||||
const [contact, setViewSafetyNumber] = React.useState<
|
|
||||||
ConversationType | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
const onClose = contact
|
|
||||||
? () => {
|
|
||||||
setViewSafetyNumber(undefined);
|
|
||||||
}
|
|
||||||
: onCancel;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConfirmationModal actions={[]} i18n={i18n} onClose={onClose}>
|
|
||||||
{contact && renderSafetyNumber({ contactID: contact.id, onClose })}
|
|
||||||
{!contact && (
|
|
||||||
<SafetyDialogContents
|
|
||||||
{...props}
|
|
||||||
onView={selectedContact => {
|
|
||||||
setViewSafetyNumber(selectedContact);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ConfirmationModal>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,8 +41,8 @@ export const SafetyNumberViewer = ({
|
||||||
|
|
||||||
if (!contact.phoneNumber) {
|
if (!contact.phoneNumber) {
|
||||||
return (
|
return (
|
||||||
<div className="module-safety-number">
|
<div className="module-SafetyNumberViewer">
|
||||||
<div className="module-safety-number__verify-container">
|
<div className="module-SafetyNumberViewer__verify-container">
|
||||||
{i18n('cannotGenerateSafetyNumber')}
|
{i18n('cannotGenerateSafetyNumber')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,7 +54,7 @@ export const SafetyNumberViewer = ({
|
||||||
showNumber && contact.phoneNumber ? ` · ${contact.phoneNumber}` : '';
|
showNumber && contact.phoneNumber ? ` · ${contact.phoneNumber}` : '';
|
||||||
const name = `${contact.title}${numberFragment}`;
|
const name = `${contact.title}${numberFragment}`;
|
||||||
const boldName = (
|
const boldName = (
|
||||||
<span className="module-safety-number__bold-name">{name}</span>
|
<span className="module-SafetyNumberViewer__bold-name">{name}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isVerified } = contact;
|
const { isVerified } = contact;
|
||||||
|
@ -65,15 +65,15 @@ export const SafetyNumberViewer = ({
|
||||||
const verifyButtonText = isVerified ? i18n('unverify') : i18n('verify');
|
const verifyButtonText = isVerified ? i18n('unverify') : i18n('verify');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-safety-number">
|
<div className="module-SafetyNumberViewer">
|
||||||
{onClose && (
|
{onClose && (
|
||||||
<div className="module-safety-number__close-button">
|
<div className="module-SafetyNumberViewer__close-button">
|
||||||
<button onClick={onClose} tabIndex={0} type="button">
|
<button onClick={onClose} tabIndex={0} type="button">
|
||||||
<span />
|
<span />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="module-safety-number__verification-label">
|
<div className="module-SafetyNumberViewer__verification-label">
|
||||||
<Intl
|
<Intl
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
id={safetyNumberChangedKey}
|
id={safetyNumberChangedKey}
|
||||||
|
@ -83,21 +83,21 @@ export const SafetyNumberViewer = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="module-safety-number__number">
|
<div className="module-SafetyNumberViewer__number">
|
||||||
{safetyNumber || getPlaceholder()}
|
{safetyNumber || getPlaceholder()}
|
||||||
</div>
|
</div>
|
||||||
<Intl i18n={i18n} id="verifyHelp" components={[boldName]} />
|
<Intl i18n={i18n} id="verifyHelp" components={[boldName]} />
|
||||||
<div className="module-safety-number__verification-status">
|
<div className="module-SafetyNumberViewer__verification-status">
|
||||||
{isVerified ? (
|
{isVerified ? (
|
||||||
<span className="module-safety-number__icon--verified" />
|
<span className="module-SafetyNumberViewer__icon--verified" />
|
||||||
) : (
|
) : (
|
||||||
<span className="module-safety-number__icon--shield" />
|
<span className="module-SafetyNumberViewer__icon--shield" />
|
||||||
)}
|
)}
|
||||||
<Intl i18n={i18n} id={verifiedStatusKey} components={[boldName]} />
|
<Intl i18n={i18n} id={verifiedStatusKey} components={[boldName]} />
|
||||||
</div>
|
</div>
|
||||||
<div className="module-safety-number__verify-container">
|
<div className="module-SafetyNumberViewer__verify-container">
|
||||||
<button
|
<button
|
||||||
className="module-safety-number__button--verify"
|
className="module-SafetyNumberViewer__button--verify"
|
||||||
disabled={verificationDisabled}
|
disabled={verificationDisabled}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
toggleVerified(contact);
|
toggleVerified(contact);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ContactName, PropsType as ContactNameProps } from './ContactName';
|
import { ContactName, PropsType as ContactNameProps } from './ContactName';
|
||||||
import { ConfirmationModal } from '../ConfirmationModal';
|
import { ConfirmationDialog } from '../ConfirmationDialog';
|
||||||
import { Intl } from '../Intl';
|
import { Intl } from '../Intl';
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
}: Props): JSX.Element | null => {
|
}: Props): JSX.Element | null => {
|
||||||
if (state === MessageRequestState.blocking) {
|
if (state === MessageRequestState.blocking) {
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
onChangeState(MessageRequestState.default);
|
onChangeState(MessageRequestState.default);
|
||||||
|
@ -77,13 +77,13 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{i18n(`MessageRequests--block-${conversationType}-confirm-body`)}
|
{i18n(`MessageRequests--block-${conversationType}-confirm-body`)}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state === MessageRequestState.unblocking) {
|
if (state === MessageRequestState.unblocking) {
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
onChangeState(MessageRequestState.default);
|
onChangeState(MessageRequestState.default);
|
||||||
|
@ -113,13 +113,13 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{i18n(`MessageRequests--unblock-${conversationType}-confirm-body`)}
|
{i18n(`MessageRequests--unblock-${conversationType}-confirm-body`)}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state === MessageRequestState.deleting) {
|
if (state === MessageRequestState.deleting) {
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
onChangeState(MessageRequestState.default);
|
onChangeState(MessageRequestState.default);
|
||||||
|
@ -149,7 +149,7 @@ export const MessageRequestActionsConfirmation = ({
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{i18n(`MessageRequests--delete-${conversationType}-confirm-body`)}
|
{i18n(`MessageRequests--delete-${conversationType}-confirm-body`)}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { LocalizerType } from '../../../types/Util';
|
import { LocalizerType } from '../../../types/Util';
|
||||||
import { ConfirmationModal } from '../../ConfirmationModal';
|
import { ConfirmationDialog } from '../../ConfirmationDialog';
|
||||||
import { Tooltip, TooltipPlacement } from '../../Tooltip';
|
import { Tooltip, TooltipPlacement } from '../../Tooltip';
|
||||||
|
|
||||||
import { PanelRow } from './PanelRow';
|
import { PanelRow } from './PanelRow';
|
||||||
|
@ -88,7 +88,7 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
|
||||||
</PanelSection>
|
</PanelSection>
|
||||||
|
|
||||||
{confirmingLeave && (
|
{confirmingLeave && (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
text: i18n(
|
text: i18n(
|
||||||
|
@ -103,11 +103,11 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
|
||||||
title={i18n('ConversationDetailsActions--leave-group-modal-title')}
|
title={i18n('ConversationDetailsActions--leave-group-modal-title')}
|
||||||
>
|
>
|
||||||
{i18n('ConversationDetailsActions--leave-group-modal-content')}
|
{i18n('ConversationDetailsActions--leave-group-modal-content')}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{confirmingBlock && (
|
{confirmingBlock && (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
text: i18n(
|
text: i18n(
|
||||||
|
@ -124,7 +124,7 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
|
||||||
])}
|
])}
|
||||||
>
|
>
|
||||||
{i18n('ConversationDetailsActions--block-group-modal-content')}
|
{i18n('ConversationDetailsActions--block-group-modal-content')}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import _ from 'lodash';
|
||||||
import { ConversationType } from '../../../state/ducks/conversations';
|
import { ConversationType } from '../../../state/ducks/conversations';
|
||||||
import { LocalizerType } from '../../../types/Util';
|
import { LocalizerType } from '../../../types/Util';
|
||||||
import { Avatar } from '../../Avatar';
|
import { Avatar } from '../../Avatar';
|
||||||
import { ConfirmationModal } from '../../ConfirmationModal';
|
import { ConfirmationDialog } from '../../ConfirmationDialog';
|
||||||
import { PanelSection } from './PanelSection';
|
import { PanelSection } from './PanelSection';
|
||||||
import { PanelRow } from './PanelRow';
|
import { PanelRow } from './PanelRow';
|
||||||
import { ConversationDetailsIcon } from './ConversationDetailsIcon';
|
import { ConversationDetailsIcon } from './ConversationDetailsIcon';
|
||||||
|
@ -206,7 +206,7 @@ function MembershipActionConfirmation({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
action: modalAction,
|
action: modalAction,
|
||||||
|
@ -223,7 +223,7 @@ function MembershipActionConfirmation({
|
||||||
ourConversationId,
|
ourConversationId,
|
||||||
stagedMemberships,
|
stagedMemberships,
|
||||||
})}
|
})}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { StickerPackInstallButton } from './StickerPackInstallButton';
|
import { StickerPackInstallButton } from './StickerPackInstallButton';
|
||||||
import { ConfirmationModal } from '../ConfirmationModal';
|
import { ConfirmationDialog } from '../ConfirmationDialog';
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
import { StickerPackType } from '../../state/ducks/stickers';
|
import { StickerPackType } from '../../state/ducks/stickers';
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ export const StickerManagerPackRow = React.memo(
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{uninstalling ? (
|
{uninstalling ? (
|
||||||
<ConfirmationModal
|
<ConfirmationDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClose={clearUninstalling}
|
onClose={clearUninstalling}
|
||||||
actions={[
|
actions={[
|
||||||
|
@ -103,7 +103,7 @@ export const StickerManagerPackRow = React.memo(
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{i18n('stickers--StickerManager--UninstallWarning')}
|
{i18n('stickers--StickerManager--UninstallWarning')}
|
||||||
</ConfirmationModal>
|
</ConfirmationDialog>
|
||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
|
|
@ -140,7 +140,7 @@ export const StickerPreviewModal = React.memo((props: Props) => {
|
||||||
}
|
}
|
||||||
uninstallStickerPack(pack.id, pack.key);
|
uninstallStickerPack(pack.id, pack.key);
|
||||||
setConfirmingUninstall(false);
|
setConfirmingUninstall(false);
|
||||||
// onClose is called by the confirmation modal
|
// onClose is called by <ConfirmationDialog />
|
||||||
}, [uninstallStickerPack, setConfirmingUninstall, pack]);
|
}, [uninstallStickerPack, setConfirmingUninstall, pack]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
// This file is here temporarily while we're switching off of Backbone into
|
// This file is here temporarily while we're switching off of Backbone into
|
||||||
// React. In the future, and in React-land, please just import and use
|
// React. In the future, and in React-land, please just import and use
|
||||||
// ConfirmationModal directly. This is the thin API layer to bridge the gap
|
// ConfirmationDialog directly. This is the thin API layer to bridge the gap
|
||||||
// while we convert things over. Please delete this file once all usages are
|
// while we convert things over. Please delete this file once all usages are
|
||||||
// ported over. Note: this file cannot have any imports/exports since it is
|
// ported over. Note: this file cannot have any imports/exports since it is
|
||||||
// being included in a <script /> tag.
|
// being included in a <script /> tag.
|
||||||
|
@ -49,11 +49,10 @@ function showConfirmationDialog(options: ConfirmationDialogViewProps) {
|
||||||
|
|
||||||
window.ReactDOM.render(
|
window.ReactDOM.render(
|
||||||
// eslint-disable-next-line react/react-in-jsx-scope, react/jsx-no-undef
|
// eslint-disable-next-line react/react-in-jsx-scope, react/jsx-no-undef
|
||||||
<window.Signal.Components.ConfirmationModal
|
<window.Signal.Components.ConfirmationDialog
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
action: () => {
|
action: () => {
|
||||||
removeConfirmationDialog();
|
|
||||||
options.resolve();
|
options.resolve();
|
||||||
},
|
},
|
||||||
style: options.confirmStyle,
|
style: options.confirmStyle,
|
||||||
|
@ -62,11 +61,13 @@ function showConfirmationDialog(options: ConfirmationDialogViewProps) {
|
||||||
]}
|
]}
|
||||||
cancelText={options.cancelText || window.i18n('cancel')}
|
cancelText={options.cancelText || window.i18n('cancel')}
|
||||||
i18n={window.i18n}
|
i18n={window.i18n}
|
||||||
|
onCancel={() => {
|
||||||
|
if (options.reject) {
|
||||||
|
options.reject(new Error('showConfirmationDialog: onCancel called'));
|
||||||
|
}
|
||||||
|
}}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
removeConfirmationDialog();
|
removeConfirmationDialog();
|
||||||
if (options.reject) {
|
|
||||||
options.reject(new Error('showConfirmationDialog: onClose called'));
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
title={options.message}
|
title={options.message}
|
||||||
/>,
|
/>,
|
||||||
|
|
|
@ -16433,7 +16433,7 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/SafetyNumberChangeDialog.js",
|
"path": "ts/components/SafetyNumberChangeDialog.js",
|
||||||
"line": " const cancelButtonRef = React.createRef();",
|
"line": " const cancelButtonRef = React.createRef();",
|
||||||
"lineNumber": 30,
|
"lineNumber": 33,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-06-23T06:48:06.829Z",
|
"updated": "2020-06-23T06:48:06.829Z",
|
||||||
"reasonDetail": "Used to focus cancel button when dialog opens"
|
"reasonDetail": "Used to focus cancel button when dialog opens"
|
||||||
|
@ -17055,4 +17055,4 @@
|
||||||
"updated": "2021-01-08T15:46:32.143Z",
|
"updated": "2021-01-08T15:46:32.143Z",
|
||||||
"reasonDetail": "Doesn't manipulate the DOM. This is just a function."
|
"reasonDetail": "Doesn't manipulate the DOM. This is just a function."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
4
ts/window.d.ts
vendored
4
ts/window.d.ts
vendored
|
@ -81,7 +81,7 @@ import { combineNames } from './util';
|
||||||
import { BatcherType } from './util/batcher';
|
import { BatcherType } from './util/batcher';
|
||||||
import { AttachmentList } from './components/conversation/AttachmentList';
|
import { AttachmentList } from './components/conversation/AttachmentList';
|
||||||
import { CaptionEditor } from './components/CaptionEditor';
|
import { CaptionEditor } from './components/CaptionEditor';
|
||||||
import { ConfirmationModal } from './components/ConfirmationModal';
|
import { ConfirmationDialog } from './components/ConfirmationDialog';
|
||||||
import { ContactDetail } from './components/conversation/ContactDetail';
|
import { ContactDetail } from './components/conversation/ContactDetail';
|
||||||
import { ContactModal } from './components/conversation/ContactModal';
|
import { ContactModal } from './components/conversation/ContactModal';
|
||||||
import { ErrorModal } from './components/ErrorModal';
|
import { ErrorModal } from './components/ErrorModal';
|
||||||
|
@ -460,7 +460,7 @@ declare global {
|
||||||
Components: {
|
Components: {
|
||||||
AttachmentList: typeof AttachmentList;
|
AttachmentList: typeof AttachmentList;
|
||||||
CaptionEditor: typeof CaptionEditor;
|
CaptionEditor: typeof CaptionEditor;
|
||||||
ConfirmationModal: typeof ConfirmationModal;
|
ConfirmationDialog: typeof ConfirmationDialog;
|
||||||
ContactDetail: typeof ContactDetail;
|
ContactDetail: typeof ContactDetail;
|
||||||
ContactModal: typeof ContactModal;
|
ContactModal: typeof ContactModal;
|
||||||
ErrorModal: typeof ErrorModal;
|
ErrorModal: typeof ErrorModal;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue