diff --git a/.stylelintrc.js b/.stylelintrc.js index c044b19a63..0bdea3cccd 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -11,7 +11,8 @@ module.exports = { "length-zero-no-unit": null, "rule-empty-line-before": null, "color-hex-length": null, - "max-empty-lines": null, + "max-empty-lines": 1, + "no-eol-whitespace": true, "number-no-trailing-zeros": null, "number-leading-zero": null, "selector-list-comma-newline-after": null, diff --git a/CHANGELOG.md b/CHANGELOG.md index f133398724..e6fa6c3c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,93 @@ +Changes in [3.33.0](https://github.com/vector-im/element-desktop/releases/tag/v3.33.0) (2021-10-25) +=================================================================================================== + +## ✨ Features + * Convert the "Cryptography" settings panel to an HTML table to assist screen reader users. ([\#6968](https://github.com/matrix-org/matrix-react-sdk/pull/6968)). Contributed by [andybalaam](https://github.com/andybalaam). + * Swap order of private space creation and tweak copy ([\#6967](https://github.com/matrix-org/matrix-react-sdk/pull/6967)). Fixes vector-im/element-web#18768 and vector-im/element-web#18768. + * Add spacing to Room settings - Notifications subsection ([\#6962](https://github.com/matrix-org/matrix-react-sdk/pull/6962)). Contributed by [CicadaCinema](https://github.com/CicadaCinema). + * Use HTML tables for some tabular user interface areas, to assist with screen reader use ([\#6955](https://github.com/matrix-org/matrix-react-sdk/pull/6955)). Contributed by [andybalaam](https://github.com/andybalaam). + * Fix space invite edge cases ([\#6884](https://github.com/matrix-org/matrix-react-sdk/pull/6884)). Fixes vector-im/element-web#19010 vector-im/element-web#17345 and vector-im/element-web#19010. + * Allow options to cascade kicks/bans throughout spaces ([\#6829](https://github.com/matrix-org/matrix-react-sdk/pull/6829)). Fixes vector-im/element-web#18969 and vector-im/element-web#18969. + * Make public space alias field mandatory again ([\#6921](https://github.com/matrix-org/matrix-react-sdk/pull/6921)). Fixes vector-im/element-web#19003 and vector-im/element-web#19003. + * Add progress bar to restricted room upgrade dialog ([\#6919](https://github.com/matrix-org/matrix-react-sdk/pull/6919)). Fixes vector-im/element-web#19146 and vector-im/element-web#19146. + * Add customisation point for visibility of invites and room creation ([\#6922](https://github.com/matrix-org/matrix-react-sdk/pull/6922)). Fixes vector-im/element-web#19331 and vector-im/element-web#19331. + * Inhibit `Unable to get validated threepid` error during UIA ([\#6928](https://github.com/matrix-org/matrix-react-sdk/pull/6928)). Fixes vector-im/element-web#18883 and vector-im/element-web#18883. + * Tweak room list skeleton UI height and behaviour ([\#6926](https://github.com/matrix-org/matrix-react-sdk/pull/6926)). Fixes vector-im/element-web#18231 vector-im/element-web#16581 and vector-im/element-web#18231. + * If public room creation fails, retry without publishing it ([\#6872](https://github.com/matrix-org/matrix-react-sdk/pull/6872)). Fixes vector-im/element-web#19194 and vector-im/element-web#19194. Contributed by [AndrewFerr](https://github.com/AndrewFerr). + * Iterate invite your teammates to Space view ([\#6925](https://github.com/matrix-org/matrix-react-sdk/pull/6925)). Fixes vector-im/element-web#18772 and vector-im/element-web#18772. + * Make placeholder more grey when no input ([\#6840](https://github.com/matrix-org/matrix-react-sdk/pull/6840)). Fixes vector-im/element-web#17243 and vector-im/element-web#17243. Contributed by [wlach](https://github.com/wlach). + * Respect tombstones in locally known rooms for Space children ([\#6906](https://github.com/matrix-org/matrix-react-sdk/pull/6906)). Fixes vector-im/element-web#19246 vector-im/element-web#19256 and vector-im/element-web#19246. + * Improve emoji shortcodes generated from annotations ([\#6907](https://github.com/matrix-org/matrix-react-sdk/pull/6907)). Fixes vector-im/element-web#19304 and vector-im/element-web#19304. + * Hide kick & ban options in UserInfo when looking at own profile ([\#6911](https://github.com/matrix-org/matrix-react-sdk/pull/6911)). Fixes vector-im/element-web#19066 and vector-im/element-web#19066. + * Add progress bar to Community to Space migration tool ([\#6887](https://github.com/matrix-org/matrix-react-sdk/pull/6887)). Fixes vector-im/element-web#19216 and vector-im/element-web#19216. + +## 🐛 Bug Fixes + * Fix leave space cancel button exploding ([\#6966](https://github.com/matrix-org/matrix-react-sdk/pull/6966)). + * Fix edge case behaviour of the space join spinner for guests ([\#6972](https://github.com/matrix-org/matrix-react-sdk/pull/6972)). Fixes vector-im/element-web#19359 and vector-im/element-web#19359. + * Convert emoticon to emoji at the end of a line on send even if the cursor isn't there ([\#6965](https://github.com/matrix-org/matrix-react-sdk/pull/6965)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix text overflows button on Home page ([\#6898](https://github.com/matrix-org/matrix-react-sdk/pull/6898)). Fixes vector-im/element-web#19180 and vector-im/element-web#19180. Contributed by [oliver-pham](https://github.com/oliver-pham). + * Space Room View should react to join rule changes down /sync ([\#6945](https://github.com/matrix-org/matrix-react-sdk/pull/6945)). Fixes vector-im/element-web#19390 and vector-im/element-web#19390. + * Hide leave section button if user isn't in the room e.g peeking ([\#6920](https://github.com/matrix-org/matrix-react-sdk/pull/6920)). Fixes vector-im/element-web#17410 and vector-im/element-web#17410. + * Fix bug where room list would get stuck showing no rooms ([\#6939](https://github.com/matrix-org/matrix-react-sdk/pull/6939)). Fixes vector-im/element-web#19373 and vector-im/element-web#19373. + * Update room settings dialog title when room name changes ([\#6916](https://github.com/matrix-org/matrix-react-sdk/pull/6916)). Fixes vector-im/element-web#17480 and vector-im/element-web#17480. Contributed by [psrpinto](https://github.com/psrpinto). + * Fix editing losing emote-ness and rainbow-ness of messages ([\#6931](https://github.com/matrix-org/matrix-react-sdk/pull/6931)). Fixes vector-im/element-web#19350 and vector-im/element-web#19350. + * Remove semicolon from notifications panel ([\#6930](https://github.com/matrix-org/matrix-react-sdk/pull/6930)). Contributed by [robintown](https://github.com/robintown). + * Prevent profile image in left panel's backdrop from being selected ([\#6924](https://github.com/matrix-org/matrix-react-sdk/pull/6924)). Contributed by [rom4nik](https://github.com/rom4nik). + * Validate that the phone number verification field is filled before allowing user to submit ([\#6918](https://github.com/matrix-org/matrix-react-sdk/pull/6918)). Fixes vector-im/element-web#19316 and vector-im/element-web#19316. Contributed by [VFermat](https://github.com/VFermat). + * Updated how save button becomes disabled in room settings to listen for all fields instead of the most recent ([\#6917](https://github.com/matrix-org/matrix-react-sdk/pull/6917)). Contributed by [LoganArnett](https://github.com/LoganArnett). + * Use FocusLock around ContextMenus to simplify focus management ([\#6311](https://github.com/matrix-org/matrix-react-sdk/pull/6311)). Fixes vector-im/element-web#19259 and vector-im/element-web#19259. + * Fix space hierarchy pagination ([\#6908](https://github.com/matrix-org/matrix-react-sdk/pull/6908)). Fixes vector-im/element-web#19276 and vector-im/element-web#19276. + * Fix spaces keyboard shortcuts not working for last space ([\#6909](https://github.com/matrix-org/matrix-react-sdk/pull/6909)). Fixes vector-im/element-web#19255 and vector-im/element-web#19255. + * Use fallback avatar only for DMs with 2 people. ([\#6895](https://github.com/matrix-org/matrix-react-sdk/pull/6895)). Fixes vector-im/element-web#18747 and vector-im/element-web#18747. Contributed by [andybalaam](https://github.com/andybalaam). + +Changes in [3.33.0-rc.2](https://github.com/vector-im/element-desktop/releases/tag/v3.33.0-rc.2) (2021-10-20) +============================================================================================================= + +## 🐛 Bug Fixes + * Fix conflicting CSS on syntax highlighted blocks ([\#6991](https://github.com/matrix-org/matrix-react-sdk/pull/6991)). Fixes vector-im/element-web#19445 + +Changes in [3.33.0-rc.1](https://github.com/vector-im/element-desktop/releases/tag/v3.33.0-rc.1) (2021-10-19) +============================================================================================================= + +## ✨ Features + * Swap order of private space creation and tweak copy ([\#6967](https://github.com/matrix-org/matrix-react-sdk/pull/6967)). Fixes vector-im/element-web#18768 and vector-im/element-web#18768. + * Add spacing to Room settings - Notifications subsection ([\#6962](https://github.com/matrix-org/matrix-react-sdk/pull/6962)). Contributed by [CicadaCinema](https://github.com/CicadaCinema). + * Convert the "Cryptography" settings panel to an HTML to assist screen reader users. ([\#6968](https://github.com/matrix-org/matrix-react-sdk/pull/6968)). Contributed by [andybalaam](https://github.com/andybalaam). + * Use HTML tables for some tabular user interface areas, to assist with screen reader use ([\#6955](https://github.com/matrix-org/matrix-react-sdk/pull/6955)). Contributed by [andybalaam](https://github.com/andybalaam). + * Fix space invite edge cases ([\#6884](https://github.com/matrix-org/matrix-react-sdk/pull/6884)). Fixes vector-im/element-web#19010 vector-im/element-web#17345 and vector-im/element-web#19010. + * Allow options to cascade kicks/bans throughout spaces ([\#6829](https://github.com/matrix-org/matrix-react-sdk/pull/6829)). Fixes vector-im/element-web#18969 and vector-im/element-web#18969. + * Make public space alias field mandatory again ([\#6921](https://github.com/matrix-org/matrix-react-sdk/pull/6921)). Fixes vector-im/element-web#19003 and vector-im/element-web#19003. + * Add progress bar to restricted room upgrade dialog ([\#6919](https://github.com/matrix-org/matrix-react-sdk/pull/6919)). Fixes vector-im/element-web#19146 and vector-im/element-web#19146. + * Add customisation point for visibility of invites and room creation ([\#6922](https://github.com/matrix-org/matrix-react-sdk/pull/6922)). Fixes vector-im/element-web#19331 and vector-im/element-web#19331. + * Inhibit `Unable to get validated threepid` error during UIA ([\#6928](https://github.com/matrix-org/matrix-react-sdk/pull/6928)). Fixes vector-im/element-web#18883 and vector-im/element-web#18883. + * Tweak room list skeleton UI height and behaviour ([\#6926](https://github.com/matrix-org/matrix-react-sdk/pull/6926)). Fixes vector-im/element-web#18231 vector-im/element-web#16581 and vector-im/element-web#18231. + * If public room creation fails, retry without publishing it ([\#6872](https://github.com/matrix-org/matrix-react-sdk/pull/6872)). Fixes vector-im/element-web#19194 and vector-im/element-web#19194. Contributed by [AndrewFerr](https://github.com/AndrewFerr). + * Iterate invite your teammates to Space view ([\#6925](https://github.com/matrix-org/matrix-react-sdk/pull/6925)). Fixes vector-im/element-web#18772 and vector-im/element-web#18772. + * Make placeholder more grey when no input ([\#6840](https://github.com/matrix-org/matrix-react-sdk/pull/6840)). Fixes vector-im/element-web#17243 and vector-im/element-web#17243. Contributed by [wlach](https://github.com/wlach). + * Respect tombstones in locally known rooms for Space children ([\#6906](https://github.com/matrix-org/matrix-react-sdk/pull/6906)). Fixes vector-im/element-web#19246 vector-im/element-web#19256 and vector-im/element-web#19246. + * Improve emoji shortcodes generated from annotations ([\#6907](https://github.com/matrix-org/matrix-react-sdk/pull/6907)). Fixes vector-im/element-web#19304 and vector-im/element-web#19304. + * Hide kick & ban options in UserInfo when looking at own profile ([\#6911](https://github.com/matrix-org/matrix-react-sdk/pull/6911)). Fixes vector-im/element-web#19066 and vector-im/element-web#19066. + * Add progress bar to Community to Space migration tool ([\#6887](https://github.com/matrix-org/matrix-react-sdk/pull/6887)). Fixes vector-im/element-web#19216 and vector-im/element-web#19216. + +## 🐛 Bug Fixes + * Fix leave space cancel button exploding ([\#6966](https://github.com/matrix-org/matrix-react-sdk/pull/6966)). + * Fix edge case behaviour of the space join spinner for guests ([\#6972](https://github.com/matrix-org/matrix-react-sdk/pull/6972)). Fixes vector-im/element-web#19359 and vector-im/element-web#19359. + * Convert emoticon to emoji at the end of a line on send even if the cursor isn't there ([\#6965](https://github.com/matrix-org/matrix-react-sdk/pull/6965)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix text overflows button on Home page ([\#6898](https://github.com/matrix-org/matrix-react-sdk/pull/6898)). Fixes vector-im/element-web#19180 and vector-im/element-web#19180. Contributed by [oliver-pham](https://github.com/oliver-pham). + * Space Room View should react to join rule changes down /sync ([\#6945](https://github.com/matrix-org/matrix-react-sdk/pull/6945)). Fixes vector-im/element-web#19390 and vector-im/element-web#19390. + * Hide leave section button if user isn't in the room e.g peeking ([\#6920](https://github.com/matrix-org/matrix-react-sdk/pull/6920)). Fixes vector-im/element-web#17410 and vector-im/element-web#17410. + * Fix bug where room list would get stuck showing no rooms ([\#6939](https://github.com/matrix-org/matrix-react-sdk/pull/6939)). Fixes vector-im/element-web#19373 and vector-im/element-web#19373. + * Update room settings dialog title when room name changes ([\#6916](https://github.com/matrix-org/matrix-react-sdk/pull/6916)). Fixes vector-im/element-web#17480 and vector-im/element-web#17480. Contributed by [psrpinto](https://github.com/psrpinto). + * Fix editing losing emote-ness and rainbow-ness of messages ([\#6931](https://github.com/matrix-org/matrix-react-sdk/pull/6931)). Fixes vector-im/element-web#19350 and vector-im/element-web#19350. + * Remove semicolon from notifications panel ([\#6930](https://github.com/matrix-org/matrix-react-sdk/pull/6930)). Contributed by [robintown](https://github.com/robintown). + * Prevent profile image in left panel's backdrop from being selected ([\#6924](https://github.com/matrix-org/matrix-react-sdk/pull/6924)). Contributed by [rom4nik](https://github.com/rom4nik). + * Validate that the phone number verification field is filled before allowing user to submit ([\#6918](https://github.com/matrix-org/matrix-react-sdk/pull/6918)). Fixes vector-im/element-web#19316 and vector-im/element-web#19316. Contributed by [VFermat](https://github.com/VFermat). + * Updated how save button becomes disabled in room settings to listen for all fields instead of the most recent ([\#6917](https://github.com/matrix-org/matrix-react-sdk/pull/6917)). Contributed by [LoganArnett](https://github.com/LoganArnett). + * Use FocusLock around ContextMenus to simplify focus management ([\#6311](https://github.com/matrix-org/matrix-react-sdk/pull/6311)). Fixes vector-im/element-web#19259 and vector-im/element-web#19259. + * Fix space hierarchy pagination ([\#6908](https://github.com/matrix-org/matrix-react-sdk/pull/6908)). Fixes vector-im/element-web#19276 and vector-im/element-web#19276. + * Fix spaces keyboard shortcuts not working for last space ([\#6909](https://github.com/matrix-org/matrix-react-sdk/pull/6909)). Fixes vector-im/element-web#19255 and vector-im/element-web#19255. + * Use fallback avatar only for DMs with 2 people. ([\#6895](https://github.com/matrix-org/matrix-react-sdk/pull/6895)). Fixes vector-im/element-web#18747 and vector-im/element-web#18747. Contributed by [andybalaam](https://github.com/andybalaam). + Changes in [3.32.1](https://github.com/vector-im/element-desktop/releases/tag/v3.32.1) (2021-10-12) =================================================================================================== diff --git a/package.json b/package.json index 02eb6f4c05..55b06cac8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.32.1", + "version": "3.33.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { diff --git a/res/css/_common.scss b/res/css/_common.scss index d90893b8ed..1284a5c499 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -141,12 +141,6 @@ input[type=search]::-webkit-search-results-decoration { input::placeholder, textarea::placeholder { opacity: initial; - font-weight: 400; -} -input::-moz-placeholder, -textarea::-moz-placeholder { - opacity: .6; - font-weight: 400; } input[type=text], input[type=password], textarea { diff --git a/res/css/_components.scss b/res/css/_components.scss index 26e36b8cdd..73e25d314f 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -200,10 +200,10 @@ @import "./views/right_panel/_EncryptionInfo.scss"; @import "./views/right_panel/_PinnedMessagesCard.scss"; @import "./views/right_panel/_RoomSummaryCard.scss"; +@import "./views/right_panel/_ThreadPanel.scss"; @import "./views/right_panel/_UserInfo.scss"; @import "./views/right_panel/_VerificationPanel.scss"; @import "./views/right_panel/_WidgetCard.scss"; -@import "./views/right_panel/_ThreadPanel.scss"; @import "./views/room_settings/_AliasSettings.scss"; @import "./views/rooms/_AppsDrawer.scss"; @import "./views/rooms/_Autocomplete.scss"; diff --git a/res/css/structures/_CreateRoom.scss b/res/css/structures/_CreateRoom.scss index 3d23ccc4b2..78e6881b10 100644 --- a/res/css/structures/_CreateRoom.scss +++ b/res/css/structures/_CreateRoom.scss @@ -34,4 +34,3 @@ limitations under the License. .mx_CreateRoom_description { width: 330px; } - diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 5ddea244f3..a658005821 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -43,8 +43,6 @@ $roomListCollapsedWidth: 68px; } } - - .mx_LeftPanel { background-color: $roomlist-bg-color; // TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index fd9c4a14fc..50fa304bd6 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -32,7 +32,6 @@ limitations under the License. position: relative; } - @keyframes mx_RoomView_fileDropTarget_animation { from { opacity: 0; @@ -112,7 +111,6 @@ limitations under the License. max-width: 1920px !important; } - .mx_RoomView .mx_MainSplit { flex: 1 1 0; } diff --git a/res/css/structures/_SpaceHierarchy.scss b/res/css/structures/_SpaceHierarchy.scss index a5d589f9c2..5735ef016d 100644 --- a/res/css/structures/_SpaceHierarchy.scss +++ b/res/css/structures/_SpaceHierarchy.scss @@ -203,7 +203,8 @@ limitations under the License. grid-row: 1; grid-column: 2; - .mx_InfoTooltip { + .mx_InfoTooltip, + .mx_SpaceHierarchy_roomTile_joined { display: inline; margin-left: 12px; color: $tertiary-content; @@ -222,6 +223,25 @@ limitations under the License. } } } + + .mx_SpaceHierarchy_roomTile_joined { + position: relative; + padding-left: 16px; + + &::before { + content: ''; + width: 20px; + height: 20px; + top: -2px; + left: -4px; + position: absolute; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background-color: $accent-color; + mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg'); + } + } } .mx_SpaceHierarchy_roomTile_info { @@ -268,6 +288,11 @@ limitations under the License. visibility: visible; } } + + &.mx_SpaceHierarchy_joining .mx_AccessibleButton { + visibility: visible; + padding: 4px 18px; + } } li.mx_SpaceHierarchy_roomTileWrapper { diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index f590de18c1..4be9d49120 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -348,7 +348,6 @@ $activeBorderColor: $secondary-content; } } - .mx_SpacePanel_sharePublicSpace { margin: 0; } diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index e6394525c5..51b5244c5f 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -380,45 +380,6 @@ $SpaceRoomViewInnerWidth: 428px; } } - .mx_SpaceRoomView_betaWarning { - padding: 12px 12px 12px 54px; - position: relative; - font-size: $font-15px; - line-height: $font-24px; - width: 432px; - border-radius: 8px; - background-color: $info-plinth-bg-color; - color: $secondary-content; - box-sizing: border-box; - - > h3 { - font-weight: $font-semi-bold; - font-size: inherit; - line-height: inherit; - margin: 0; - } - - > p { - font-size: inherit; - line-height: inherit; - margin: 0; - } - - &::before { - mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); - mask-position: center; - mask-repeat: no-repeat; - mask-size: contain; - content: ''; - width: 20px; - height: 20px; - position: absolute; - top: 14px; - left: 14px; - background-color: $secondary-content; - } - } - .mx_SpaceRoomView_inviteTeammates { // XXX remove this when spaces leaves Beta .mx_SpaceRoomView_inviteTeammates_betaDisclaimer { diff --git a/res/css/views/dialogs/_JoinRuleDropdown.scss b/res/css/views/dialogs/_JoinRuleDropdown.scss index 91691cf53b..19209e9536 100644 --- a/res/css/views/dialogs/_JoinRuleDropdown.scss +++ b/res/css/views/dialogs/_JoinRuleDropdown.scss @@ -64,4 +64,3 @@ limitations under the License. mask-size: contain; } } - diff --git a/res/css/views/dialogs/_MessageEditHistoryDialog.scss b/res/css/views/dialogs/_MessageEditHistoryDialog.scss index 4574344a28..f60bbc9589 100644 --- a/res/css/views/dialogs/_MessageEditHistoryDialog.scss +++ b/res/css/views/dialogs/_MessageEditHistoryDialog.scss @@ -64,4 +64,3 @@ limitations under the License. padding: 0 8px; } } - diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss index 9bcde6e1e0..cad83e2a42 100644 --- a/res/css/views/dialogs/_RoomSettingsDialog.scss +++ b/res/css/views/dialogs/_RoomSettingsDialog.scss @@ -58,4 +58,3 @@ limitations under the License. mask-size: 36px; mask-position: center; } - diff --git a/res/css/views/dialogs/_RoomUpgradeWarningDialog.scss b/res/css/views/dialogs/_RoomUpgradeWarningDialog.scss index 941c8cb807..05e7f5c2e4 100644 --- a/res/css/views/dialogs/_RoomUpgradeWarningDialog.scss +++ b/res/css/views/dialogs/_RoomUpgradeWarningDialog.scss @@ -50,4 +50,3 @@ limitations under the License. vertical-align: middle; } } - diff --git a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss index 176919b84c..8786defed3 100644 --- a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss +++ b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - .mx_WidgetCapabilitiesPromptDialog { .text-muted { font-size: $font-12px; @@ -55,7 +54,6 @@ limitations under the License. width: $font-32px; height: $font-15px; - &.mx_ToggleSwitch_on > .mx_ToggleSwitch_ball { left: calc(100% - $font-15px); } diff --git a/res/css/views/elements/_Dropdown.scss b/res/css/views/elements/_Dropdown.scss index 1acac70e42..e1e265f701 100644 --- a/res/css/views/elements/_Dropdown.scss +++ b/res/css/views/elements/_Dropdown.scss @@ -130,4 +130,3 @@ input.mx_Dropdown_option:focus { margin-left: 5px; margin-bottom: 5px; } - diff --git a/res/css/views/elements/_EditableItemList.scss b/res/css/views/elements/_EditableItemList.scss index f089fa3dc2..8987510a18 100644 --- a/res/css/views/elements/_EditableItemList.scss +++ b/res/css/views/elements/_EditableItemList.scss @@ -61,4 +61,3 @@ limitations under the License. .mx_EditableItemList_label { margin-bottom: 5px; } - diff --git a/res/css/views/elements/_Slider.scss b/res/css/views/elements/_Slider.scss index 730da021bd..3cfc14ab46 100644 --- a/res/css/views/elements/_Slider.scss +++ b/res/css/views/elements/_Slider.scss @@ -58,7 +58,6 @@ limitations under the License. height: $slider-selection-dot-size; background-color: $slider-selection-color; border-radius: 50%; - box-shadow: 0 0 6px lightgrey; z-index: 10; } diff --git a/res/css/views/elements/_StyledCheckbox.scss b/res/css/views/elements/_StyledCheckbox.scss index e2d61c033b..1467474b05 100644 --- a/res/css/views/elements/_StyledCheckbox.scss +++ b/res/css/views/elements/_StyledCheckbox.scss @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - .mx_Checkbox { $size: $font-16px; $border-size: $font-1-5px; diff --git a/res/css/views/elements/_TooltipButton.scss b/res/css/views/elements/_TooltipButton.scss index 0c85dac818..5b7c0ce14d 100644 --- a/res/css/views/elements/_TooltipButton.scss +++ b/res/css/views/elements/_TooltipButton.scss @@ -49,4 +49,3 @@ limitations under the License. text-align: start; line-height: 17px !important; } - diff --git a/res/css/views/messages/_MImageReplyBody.scss b/res/css/views/messages/_MImageReplyBody.scss index 70c53f8c9c..3207443d65 100644 --- a/res/css/views/messages/_MImageReplyBody.scss +++ b/res/css/views/messages/_MImageReplyBody.scss @@ -34,4 +34,3 @@ limitations under the License. } } } - diff --git a/res/css/views/messages/_common_CryptoEvent.scss b/res/css/views/messages/_common_CryptoEvent.scss index b400a933ae..ad986575a2 100644 --- a/res/css/views/messages/_common_CryptoEvent.scss +++ b/res/css/views/messages/_common_CryptoEvent.scss @@ -39,7 +39,6 @@ limitations under the License. background-color: $notice-primary-color; } - .mx_cryptoEvent_state, .mx_cryptoEvent_buttons { grid-column: 3; grid-row: 1 / 3; diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss index c137bb7677..e08a11cd36 100644 --- a/res/css/views/right_panel/_RoomSummaryCard.scss +++ b/res/css/views/right_panel/_RoomSummaryCard.scss @@ -83,7 +83,7 @@ limitations under the License. } .mx_RoomSummaryCard_e2ee_warning { - background-color: #ff4b55; + background-color: #ff5b55; &::before { mask-image: url('$(res)/img/e2e/warning.svg'); } diff --git a/res/css/views/right_panel/_ThreadPanel.scss b/res/css/views/right_panel/_ThreadPanel.scss index d06981a715..06137196a3 100644 --- a/res/css/views/right_panel/_ThreadPanel.scss +++ b/res/css/views/right_panel/_ThreadPanel.scss @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - .mx_ThreadPanel { display: flex; flex-direction: column; diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index 9a09d96bc9..a015ef29a7 100644 --- a/res/css/views/right_panel/_UserInfo.scss +++ b/res/css/views/right_panel/_UserInfo.scss @@ -223,7 +223,6 @@ limitations under the License. display: flex; margin: 8px 0; - &.mx_UserInfo_device_verified { .mx_UserInfo_device_trusted { color: $accent-color; @@ -267,7 +266,6 @@ limitations under the License. margin: 16px 0 8px; } - .mx_VerificationShowSas { .mx_AccessibleButton + .mx_AccessibleButton { margin: 8px 0; // space between buttons diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index 95856a5d69..0db93f58cc 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -23,7 +23,6 @@ limitations under the License. } } - .mx_UserInfo { .mx_EncryptionPanel_cancel { mask: url('$(res)/img/feather-customised/cancel.svg'); diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index cfcb0c48a2..1276b13fde 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -365,7 +365,6 @@ $MinWidth: 240px; to { opacity: 1; } } - .mx_AppLoading iframe { display: none; } diff --git a/res/css/views/rooms/_EditMessageComposer.scss b/res/css/views/rooms/_EditMessageComposer.scss index bf3c7c9b42..136ae0d4eb 100644 --- a/res/css/views/rooms/_EditMessageComposer.scss +++ b/res/css/views/rooms/_EditMessageComposer.scss @@ -24,7 +24,6 @@ limitations under the License. margin: -7px -10px -5px -10px; overflow: visible !important; // override mx_EventTile_content - .mx_BasicMessageComposer_input { border-radius: 4px; border: solid 1px $primary-hairline-color; diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 2a419530d8..1c8f4230b6 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -232,7 +232,7 @@ limitations under the License. .mx_EditMessageComposer_buttons { position: static; padding: 0; - margin: 0; + margin: 8px 0 0; background: transparent; } @@ -263,7 +263,6 @@ limitations under the License. } } - .mx_EventTile_readAvatars { position: absolute; right: -110px; diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 6e950dea84..90fd3e9203 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -401,7 +401,6 @@ $left-gutter: 64px; cursor: pointer; } - .mx_EventTile_e2eIcon { position: relative; width: 14px; @@ -486,7 +485,7 @@ $left-gutter: 64px; pre, code { font-family: $monospace-font-family !important; - background-color: $header-panel-bg-color; + background-color: $codeblock-background-color; } pre code > * { @@ -581,7 +580,6 @@ $left-gutter: 64px; color: inherit; } - /* Make h1 and h2 the same size as h3. */ .mx_EventTile_content .markdown-body h1, .mx_EventTile_content .markdown-body h2 { @@ -613,7 +611,6 @@ $left-gutter: 64px; /* end of overrides */ - .mx_EventTile_keyRequestInfo { font-size: $font-12px; } @@ -731,8 +728,6 @@ $left-gutter: 64px; } } - - .mx_ThreadView { display: flex; flex-direction: column; diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 62cbdb910a..d824e8105e 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -247,7 +247,6 @@ limitations under the License. } } - .mx_MessageComposer_upload::before { mask-image: url('$(res)/img/element-icons/room/composer/attach.svg'); } diff --git a/res/css/views/rooms/_MessageComposerFormatBar.scss b/res/css/views/rooms/_MessageComposerFormatBar.scss index b02afac079..ce7aed2dee 100644 --- a/res/css/views/rooms/_MessageComposerFormatBar.scss +++ b/res/css/views/rooms/_MessageComposerFormatBar.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_MessageComposerFormatBar { display: none; - width: calc(32px * 5); + width: calc(32px * 6); height: 32px; position: absolute; cursor: pointer; @@ -87,6 +87,11 @@ limitations under the License. .mx_MessageComposerFormatBar_buttonIconCode::after { mask-image: url('$(res)/img/element-icons/room/format-bar/code.svg'); } + + .mx_MessageComposerFormatBar_buttonIconInsertLink::after { + mask-image: url('$(res)/img/element-icons/link.svg'); + mask-size: 18px; + } } .mx_MessageComposerFormatBar_buttonTooltip { diff --git a/res/css/views/rooms/_ReplyPreview.scss b/res/css/views/rooms/_ReplyPreview.scss index 70a820e412..eb0233108b 100644 --- a/res/css/views/rooms/_ReplyPreview.scss +++ b/res/css/views/rooms/_ReplyPreview.scss @@ -52,4 +52,3 @@ limitations under the License. } } } - diff --git a/res/css/views/rooms/_ReplyTile.scss b/res/css/views/rooms/_ReplyTile.scss index 3ef6491ec9..a03f0b38cf 100644 --- a/res/css/views/rooms/_ReplyTile.scss +++ b/res/css/views/rooms/_ReplyTile.scss @@ -78,7 +78,8 @@ limitations under the License. // Hack to cut content in
tags too .mx_EventTile_pre_container > pre { - overflow: hidden; + overflow-x: scroll; + overflow-y: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index e08168a122..234363245a 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -68,4 +68,3 @@ limitations under the License. cursor: pointer; } } - diff --git a/res/css/views/rooms/_SendMessageComposer.scss b/res/css/views/rooms/_SendMessageComposer.scss index 4b7eb54188..c7e6ea6a6e 100644 --- a/res/css/views/rooms/_SendMessageComposer.scss +++ b/res/css/views/rooms/_SendMessageComposer.scss @@ -47,4 +47,3 @@ limitations under the License. } } } - diff --git a/res/css/views/settings/_E2eAdvancedPanel.scss b/res/css/views/settings/_E2eAdvancedPanel.scss index 9e32685d12..3f180e6fcd 100644 --- a/res/css/views/settings/_E2eAdvancedPanel.scss +++ b/res/css/views/settings/_E2eAdvancedPanel.scss @@ -17,4 +17,3 @@ limitations under the License. .mx_E2eAdvancedPanel_settingLongDescription { margin-right: 150px; } - diff --git a/res/css/views/settings/_ThemeChoicePanel.scss b/res/css/views/settings/_ThemeChoicePanel.scss index 39b73e7837..a335b6e68e 100644 --- a/res/css/views/settings/_ThemeChoicePanel.scss +++ b/res/css/views/settings/_ThemeChoicePanel.scss @@ -85,4 +85,3 @@ limitations under the License. } } } - diff --git a/res/css/views/voip/CallView/_CallViewButtons.scss b/res/css/views/voip/CallView/_CallViewButtons.scss index 8e343f0ff3..d9396ac3ee 100644 --- a/res/css/views/voip/CallView/_CallViewButtons.scss +++ b/res/css/views/voip/CallView/_CallViewButtons.scss @@ -35,7 +35,6 @@ limitations under the License. margin-left: 2px; margin-right: 2px; - &::before { content: ''; display: inline-block; @@ -48,7 +47,6 @@ limitations under the License. background-position: center; } - &.mx_CallViewButtons_dialpad::before { background-image: url('$(res)/img/voip/dialpad.svg'); } diff --git a/res/css/views/voip/_CallView.scss b/res/css/views/voip/_CallView.scss index aa0aa4e2a6..088486bdf6 100644 --- a/res/css/views/voip/_CallView.scss +++ b/res/css/views/voip/_CallView.scss @@ -200,7 +200,6 @@ limitations under the License. } } - .mx_CallView_presenting { opacity: 1; transition: opacity 0.5s; diff --git a/res/img/element-icons/message/thread.svg b/res/img/element-icons/message/thread.svg index b4a7cc0066..cd1271b513 100644 --- a/res/img/element-icons/message/thread.svg +++ b/res/img/element-icons/message/thread.svg @@ -1,4 +1 @@ - + \ No newline at end of file diff --git a/res/img/element-icons/room/default_cal.svg b/res/img/element-icons/room/default_cal.svg index fc440b4553..65bf98a42d 100644 --- a/res/img/element-icons/room/default_cal.svg +++ b/res/img/element-icons/room/default_cal.svg @@ -1,6 +1,6 @@ diff --git a/res/img/element-icons/warning-badge.svg b/res/img/element-icons/warning-badge.svg index 1c8da9aa8e..09e0944bdb 100644 --- a/res/img/element-icons/warning-badge.svg +++ b/res/img/element-icons/warning-badge.svg @@ -28,5 +28,5 @@+ style="fill:#ff5b55;fill-opacity:1" /> diff --git a/res/img/feather-customised/bug.svg b/res/img/feather-customised/bug.svg index babc4fed0e..8939f8be11 100644 --- a/res/img/feather-customised/bug.svg +++ b/res/img/feather-customised/bug.svg @@ -1,3 +1,3 @@ diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index ca06d38b1f..865eb4de43 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -165,6 +165,9 @@ $button-link-bg-color: transparent; // Toggle switch $togglesw-off-color: $room-highlight-color; +// Slider +$slider-background-color: $quinary-content; + $progressbar-fg-color: $accent-color; $progressbar-bg-color: $system; @@ -209,6 +212,8 @@ $appearance-tab-border-color: $room-highlight-color; $composer-shadow-color: rgba(0, 0, 0, 0.28); +$codeblock-background-color: #2a3039; + // Bubble tiles $eventbubble-self-bg: #14322E; $eventbubble-others-bg: $event-selected-color; diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index 0fe9f22dde..5fa0e903ba 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -221,6 +221,8 @@ $appearance-tab-border-color: $room-highlight-color; $composer-shadow-color: tranparent; +$codeblock-background-color: #2a3039; + // Bubble tiles $eventbubble-self-bg: #14322E; $eventbubble-others-bg: $event-selected-color; diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index 09dd46d151..7fe5649787 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -334,6 +334,8 @@ $appearance-tab-border-color: $input-darker-bg-color; $composer-shadow-color: tranparent; +$codeblock-background-color: $header-panel-bg-color; + // Bubble tiles $eventbubble-self-bg: #F0FBF8; $eventbubble-others-bg: $system; diff --git a/res/themes/light-high-contrast/css/_light-high-contrast.scss b/res/themes/light-high-contrast/css/_light-high-contrast.scss index bb5fa16056..f1f4387a06 100644 --- a/res/themes/light-high-contrast/css/_light-high-contrast.scss +++ b/res/themes/light-high-contrast/css/_light-high-contrast.scss @@ -1,11 +1,12 @@ //// Reference: https://www.figma.com/file/RnLKnv09glhxGIZtn8zfmh/UI-Themes-%26-Accessibility?node-id=321%3A65847 $accent: #268075; $alert: #D62C25; -$notice-primary-color: #D61C25; $links: #0A6ECA; $secondary-content: #5E6266; -$tertiary-content: #5E6266; // Same as secondary -$quaternary-content: #5E6266; // Same as secondary +$tertiary-content: $secondary-content; +$quaternary-content: $secondary-content; +$quinary-content: $secondary-content; +$roomlist-button-bg-color: rgba(141, 151, 165, 0.2); $username-variant1-color: #0A6ECA; $username-variant2-color: #AC3BA8; @@ -18,9 +19,13 @@ $username-variant8-color: #3E810A; $accent-color: $accent; $accent-color-50pct: rgba($accent-color, 0.5); +$accent-color-alt: $links; +$input-border-color: $secondary-content; $input-darker-bg-color: $quinary-content; +$input-darker-fg-color: $secondary-content; $input-lighter-fg-color: $input-darker-fg-color; $input-valid-border-color: $accent-color; +$input-focused-border-color: $accent-color; $button-bg-color: $accent-color; $resend-button-divider-color: $input-darker-bg-color; $icon-button-color: $quaternary-content; @@ -41,12 +46,14 @@ $voice-record-stop-border-color: $quinary-content; $voice-record-icon-color: $tertiary-content; $appearance-tab-border-color: $input-darker-bg-color; $eventbubble-reply-color: $quaternary-content; +$notice-primary-color: $alert; $warning-color: $notice-primary-color; // red $pinned-unread-color: $notice-primary-color; $button-danger-bg-color: $notice-primary-color; $mention-user-pill-bg-color: $warning-color; $input-invalid-border-color: $warning-color; $event-highlight-fg-color: $warning-color; +$roomtopic-color: $secondary-content; @define-mixin mx_DialogButton_danger { background-color: $accent-color; @@ -64,3 +71,38 @@ $event-highlight-fg-color: $warning-color; color: $accent-color; text-decoration: none; } + +.mx_AccessibleButton { + margin-left: 4px; +} + +.mx_AccessibleButton:focus { + outline: 2px solid $accent-color; + outline-offset: 2px; +} + +.mx_BasicMessageComposer .mx_BasicMessageComposer_inputEmpty > :first-child::before { + color: $secondary-content; + opacity: 1 !important; +} + +.mx_TextualEvent { + color: $secondary-content; + opacity: 1 !important; +} + +.mx_Dialog, .mx_MatrixChat_wrapper { + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text]::placeholder, + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search]::placeholder, + .mx_textinput input::placeholder { + color: $input-darker-fg-color !important; + } +} + +.mx_UserMenu_contextMenu .mx_UserMenu_contextMenu_header .mx_UserMenu_contextMenu_themeButton { + background-color: $roomlist-button-bg-color !important; +} + +.mx_FontScalingPanel_fontSlider { + background-color: $roomlist-button-bg-color !important; +} diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 1733831b95..ef4ab0115d 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -35,7 +35,7 @@ $space-nav: rgba($tertiary-content, 0.15); // try to use these colors when possible $accent-color: $accent; $accent-bg-color: rgba(3, 179, 129, 0.16); -$notice-primary-color: #ff4b55; +$notice-primary-color: $alert; $notice-primary-bg-color: rgba(255, 75, 85, 0.16); $header-panel-bg-color: #f3f8fd; @@ -318,8 +318,8 @@ $breadcrumb-placeholder-bg-color: #e8eef5; // These two don't change between themes. They are the $warning-color, but we don't // want custom themes to affect them by accident. -$voice-record-stop-symbol-color: #ff4b55; -$voice-record-live-circle-color: #ff4b55; +$voice-record-stop-symbol-color: #ff5b55; +$voice-record-live-circle-color: #ff5b55; $voice-record-stop-border-color: $quinary-content; $voice-record-icon-color: $tertiary-content; @@ -333,6 +333,8 @@ $appearance-tab-border-color: $input-darker-bg-color; } $composer-shadow-color: rgba(0, 0, 0, 0.04); +$codeblock-background-color: $header-panel-bg-color; + // Bubble tiles $eventbubble-self-bg: #F0FBF8; $eventbubble-others-bg: $system; diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 38f237b9c3..a9d8e9547f 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -99,6 +99,7 @@ declare global { mxSkinner?: Skinner; mxOnRecaptchaLoaded?: () => void; electron?: Electron; + mxSendSentryReport: (userText: string, issueUrl: string, error: Error) => Promise ; } interface DesktopCapturerSource { diff --git a/src/Modal.tsx b/src/Modal.tsx index 1e84078ddb..a802e36d96 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; -import { defer } from "matrix-js-sdk/src/utils"; +import { defer, sleep } from "matrix-js-sdk/src/utils"; import Analytics from './Analytics'; import dis from './dispatcher/dispatcher'; @@ -332,7 +332,10 @@ export class ModalManager { return this.priorityModal ? this.priorityModal : (this.modals[0] || this.staticModal); } - private reRender() { + private async reRender() { + // await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around + await sleep(0); + if (this.modals.length === 0 && !this.priorityModal && !this.staticModal) { // If there is no modal to render, make all of Element available // to screen reader users again diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 83115bcbf8..5914c8799e 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -32,6 +32,10 @@ import AccessSecretStorageDialog from './components/views/dialogs/security/Acces import RestoreKeyBackupDialog from './components/views/dialogs/security/RestoreKeyBackupDialog'; import SettingsStore from "./settings/SettingsStore"; import SecurityCustomisations from "./customisations/Security"; +import { DeviceTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning'; + +import { logger } from "matrix-js-sdk/src/logger"; +import { ComponentType } from "react"; // This stores the secret storage private keys in memory for the JS SDK. This is // only meant to act as a cache to avoid prompting the user multiple times @@ -335,7 +339,9 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f // This dialog calls bootstrap itself after guiding the user through // passphrase creation. const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '', - import("./async-components/views/dialogs/security/CreateSecretStorageDialog"), + import( + "./async-components/views/dialogs/security/CreateSecretStorageDialog" + ) as unknown as Promise >, { forceReset, }, diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index b97f5bde06..b5734d7bfc 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -1013,14 +1013,14 @@ export const Commands = [ new Command({ command: "msg", description: _td("Sends a message to the given user"), - args: " ", + args: " [ ]", runFn: function(roomId, args) { if (args) { // matches the first whitespace delimited group and then the rest of the string const matches = args.match(/^(\S+?)(?: +(.*))?$/s); if (matches) { const [userId, msg] = matches.slice(1); - if (msg && userId && userId.startsWith("@") && userId.includes(":")) { + if (userId && userId.startsWith("@") && userId.includes(":")) { return success((async () => { const cli = MatrixClientPeg.get(); const roomId = await ensureDMExists(cli, userId); @@ -1028,7 +1028,9 @@ export const Commands = [ action: 'view_room', room_id: roomId, }); - cli.sendTextMessage(roomId, msg); + if (msg) { + cli.sendTextMessage(roomId, msg); + } })()); } } diff --git a/src/Terms.ts b/src/Terms.ts index 325a132daa..4b1480f536 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -180,7 +180,7 @@ export async function startTermsFlow( return Promise.all(agreePromises); } -export function dialogTermsInteractionCallback( +export async function dialogTermsInteractionCallback( policiesAndServicePairs: { service: Service; policies: { [policy: string]: Policy }; @@ -188,21 +188,18 @@ export function dialogTermsInteractionCallback( agreedUrls: string[], extraClassNames?: string, ): Promise { - return new Promise((resolve, reject) => { - logger.log("Terms that need agreement", policiesAndServicePairs); - // FIXME: Using an import will result in test failures - const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog"); + logger.log("Terms that need agreement", policiesAndServicePairs); + // FIXME: Using an import will result in test failures + const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog"); - Modal.createTrackedDialog('Terms of Service', '', TermsDialog, { - policiesAndServicePairs, - agreedUrls, - onFinished: (done, agreedUrls) => { - if (!done) { - reject(new TermsNotSignedError()); - return; - } - resolve(agreedUrls); - }, - }, classNames("mx_TermsDialog", extraClassNames)); - }); + const { finished } = Modal.createTrackedDialog<[boolean, string[]]>('Terms of Service', '', TermsDialog, { + policiesAndServicePairs, + agreedUrls, + }, classNames("mx_TermsDialog", extraClassNames)); + + const [done, _agreedUrls] = await finished; + if (!done) { + throw new TermsNotSignedError(); + } + return _agreedUrls; } diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index 13348b2992..63ecaed642 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + import React from 'react'; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { logger } from "matrix-js-sdk/src/logger"; @@ -28,7 +29,11 @@ import { RightPanelPhases } from './stores/RightPanelStorePhases'; import { Action } from './dispatcher/actions'; import defaultDispatcher from './dispatcher/dispatcher'; import { SetRightPanelPhasePayload } from './dispatcher/payloads/SetRightPanelPhasePayload'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials"; +import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from "./MatrixClientPeg"; +import { ROOM_SECURITY_TAB } from "./components/views/dialogs/RoomSettingsDialog"; // These functions are frequently used just to check whether an event has // any text to display at all. For this reason they return deferred values @@ -201,17 +206,38 @@ function textForTombstoneEvent(ev: MatrixEvent): () => string | null { return () => _t('%(senderDisplayName)s upgraded this room.', { senderDisplayName }); } -function textForJoinRulesEvent(ev: MatrixEvent): () => string | null { +const onViewJoinRuleSettingsClick = () => { + defaultDispatcher.dispatch({ + action: "open_room_settings", + initial_tab_id: ROOM_SECURITY_TAB, + }); +}; + +function textForJoinRulesEvent(ev: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().join_rule) { - case "public": + case JoinRule.Public: return () => _t('%(senderDisplayName)s made the room public to whoever knows the link.', { senderDisplayName, }); - case "invite": + case JoinRule.Invite: return () => _t('%(senderDisplayName)s made the room invite only.', { senderDisplayName, }); + case JoinRule.Restricted: + if (allowJSX) { + return () => + { _t('%(senderDisplayName)s changed who can join this room. View settings.', { + senderDisplayName, + }, { + "a": (sub) => + { sub } + , + }) } + ; + } + + return () => _t('%(senderDisplayName)s changed who can join this room.', { senderDisplayName }); default: // The spec supports "knock" and "private", however nothing implements these. return () => _t('%(senderDisplayName)s changed the join rule to %(rule)s', { @@ -224,9 +250,9 @@ function textForJoinRulesEvent(ev: MatrixEvent): () => string | null { function textForGuestAccessEvent(ev: MatrixEvent): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().guest_access) { - case "can_join": + case GuestAccess.CanJoin: return () => _t('%(senderDisplayName)s has allowed guests to join the room.', { senderDisplayName }); - case "forbidden": + case GuestAccess.Forbidden: return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', { senderDisplayName }); default: // There's no other options we can expect, however just for safety's sake we'll do this. @@ -312,11 +338,11 @@ function textForMessageEvent(ev: MatrixEvent): () => string | null { || redactedBecauseUserId }); } } - if (ev.getContent().msgtype === "m.emote") { + if (ev.getContent().msgtype === MsgType.Emote) { message = "* " + senderDisplayName + " " + message; - } else if (ev.getContent().msgtype === "m.image") { + } else if (ev.getContent().msgtype === MsgType.Image) { message = _t('%(senderDisplayName)s sent an image.', { senderDisplayName }); - } else if (ev.getType() == "m.sticker") { + } else if (ev.getType() == EventType.Sticker) { message = _t('%(senderDisplayName)s sent a sticker.', { senderDisplayName }); } else { // in this case, parse it as a plain text message @@ -396,15 +422,15 @@ function textForThreePidInviteEvent(event: MatrixEvent): () => string | null { function textForHistoryVisibilityEvent(event: MatrixEvent): () => string | null { const senderName = event.sender ? event.sender.name : event.getSender(); switch (event.getContent().history_visibility) { - case 'invited': + case HistoryVisibility.Invited: return () => _t('%(senderName)s made future room history visible to all room members, ' + 'from the point they are invited.', { senderName }); - case 'joined': + case HistoryVisibility.Joined: return () => _t('%(senderName)s made future room history visible to all room members, ' + 'from the point they joined.', { senderName }); - case 'shared': + case HistoryVisibility.Shared: return () => _t('%(senderName)s made future room history visible to all room members.', { senderName }); - case 'world_readable': + case HistoryVisibility.WorldReadable: return () => _t('%(senderName)s made future room history visible to anyone.', { senderName }); default: return () => _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', { @@ -695,25 +721,25 @@ interface IHandlers { } const handlers: IHandlers = { - 'm.room.message': textForMessageEvent, - 'm.sticker': textForMessageEvent, - 'm.call.invite': textForCallInviteEvent, + [EventType.RoomMessage]: textForMessageEvent, + [EventType.Sticker]: textForMessageEvent, + [EventType.CallInvite]: textForCallInviteEvent, }; const stateHandlers: IHandlers = { - 'm.room.canonical_alias': textForCanonicalAliasEvent, - 'm.room.name': textForRoomNameEvent, - 'm.room.topic': textForTopicEvent, - 'm.room.member': textForMemberEvent, - "m.room.avatar": textForRoomAvatarEvent, - 'm.room.third_party_invite': textForThreePidInviteEvent, - 'm.room.history_visibility': textForHistoryVisibilityEvent, - 'm.room.power_levels': textForPowerEvent, - 'm.room.pinned_events': textForPinnedEvent, - 'm.room.server_acl': textForServerACLEvent, - 'm.room.tombstone': textForTombstoneEvent, - 'm.room.join_rules': textForJoinRulesEvent, - 'm.room.guest_access': textForGuestAccessEvent, + [EventType.RoomCanonicalAlias]: textForCanonicalAliasEvent, + [EventType.RoomName]: textForRoomNameEvent, + [EventType.RoomTopic]: textForTopicEvent, + [EventType.RoomMember]: textForMemberEvent, + [EventType.RoomAvatar]: textForRoomAvatarEvent, + [EventType.RoomThirdPartyInvite]: textForThreePidInviteEvent, + [EventType.RoomHistoryVisibility]: textForHistoryVisibilityEvent, + [EventType.RoomPowerLevels]: textForPowerEvent, + [EventType.RoomPinnedEvents]: textForPinnedEvent, + [EventType.RoomServerAcl]: textForServerACLEvent, + [EventType.RoomTombstone]: textForTombstoneEvent, + [EventType.RoomJoinRules]: textForJoinRulesEvent, + [EventType.RoomGuestAccess]: textForGuestAccessEvent, 'm.room.related_groups': textForRelatedGroupsEvent, // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx index 68e10049fd..8c49a4d6ae 100644 --- a/src/accessibility/RovingTabIndex.tsx +++ b/src/accessibility/RovingTabIndex.tsx @@ -24,6 +24,7 @@ import React, { useReducer, Reducer, Dispatch, + RefObject, } from "react"; import { Key } from "../Keyboard"; @@ -63,7 +64,7 @@ const RovingTabIndexContext = createContext ({ }); RovingTabIndexContext.displayName = "RovingTabIndexContext"; -enum Type { +export enum Type { Register = "REGISTER", Unregister = "UNREGISTER", SetFocus = "SET_FOCUS", @@ -76,73 +77,67 @@ interface IAction { }; } -const reducer = (state: IState, action: IAction) => { +export const reducer = (state: IState, action: IAction) => { switch (action.type) { case Type.Register: { - if (state.refs.length === 0) { + let left = 0; + let right = state.refs.length - 1; + let index = state.refs.length; // by default append to the end + + // do a binary search to find the right slot + while (left <= right) { + index = Math.floor((left + right) / 2); + const ref = state.refs[index]; + + if (ref === action.payload.ref) { + return state; // already in refs, this should not happen + } + + if (action.payload.ref.current.compareDocumentPosition(ref.current) & DOCUMENT_POSITION_PRECEDING) { + left = ++index; + } else { + right = index - 1; + } + } + + if (!state.activeRef) { // Our list of refs was empty, set activeRef to this first item - return { - ...state, - activeRef: action.payload.ref, - refs: [action.payload.ref], - }; - } - - if (state.refs.includes(action.payload.ref)) { - return state; // already in refs, this should not happen - } - - // find the index of the first ref which is not preceding this one in DOM order - let newIndex = state.refs.findIndex(ref => { - return ref.current.compareDocumentPosition(action.payload.ref.current) & DOCUMENT_POSITION_PRECEDING; - }); - - if (newIndex < 0) { - newIndex = state.refs.length; // append to the end + state.activeRef = action.payload.ref; } // update the refs list - return { - ...state, - refs: [ - ...state.refs.slice(0, newIndex), - action.payload.ref, - ...state.refs.slice(newIndex), - ], - }; + if (index < state.refs.length) { + state.refs.splice(index, 0, action.payload.ref); + } else { + state.refs.push(action.payload.ref); + } + return { ...state }; } - case Type.Unregister: { - // filter out the ref which we are removing - const refs = state.refs.filter(r => r !== action.payload.ref); - if (refs.length === state.refs.length) { + case Type.Unregister: { + const oldIndex = state.refs.findIndex(r => r === action.payload.ref); + + if (oldIndex === -1) { return state; // already removed, this should not happen } - if (state.activeRef === action.payload.ref) { + if (state.refs.splice(oldIndex, 1)[0] === state.activeRef) { // we just removed the active ref, need to replace it // pick the ref which is now in the index the old ref was in - const oldIndex = state.refs.findIndex(r => r === action.payload.ref); - return { - ...state, - activeRef: oldIndex >= refs.length ? refs[refs.length - 1] : refs[oldIndex], - refs, - }; + const len = state.refs.length; + state.activeRef = oldIndex >= len ? state.refs[len - 1] : state.refs[oldIndex]; } // update the refs list - return { - ...state, - refs, - }; + return { ...state }; } + case Type.SetFocus: { // update active ref - return { - ...state, - activeRef: action.payload.ref, - }; + state.activeRef = action.payload.ref; + return { ...state }; } + default: return state; } @@ -151,13 +146,40 @@ const reducer = (state: IState, action: IAction) => { interface IProps { handleHomeEnd?: boolean; handleUpDown?: boolean; + handleLeftRight?: boolean; children(renderProps: { onKeyDownHandler(ev: React.KeyboardEvent); }); onKeyDown?(ev: React.KeyboardEvent, state: IState); } -export const RovingTabIndexProvider: React.FC = ({ children, handleHomeEnd, handleUpDown, onKeyDown }) => { +export const findSiblingElement = ( + refs: RefObject [], + startIndex: number, + backwards = false, +): RefObject => { + if (backwards) { + for (let i = startIndex; i < refs.length && i >= 0; i--) { + if (refs[i].current.offsetParent !== null) { + return refs[i]; + } + } + } else { + for (let i = startIndex; i < refs.length && i >= 0; i++) { + if (refs[i].current.offsetParent !== null) { + return refs[i]; + } + } + } +}; + +export const RovingTabIndexProvider: React.FC = ({ + children, + handleHomeEnd, + handleUpDown, + handleLeftRight, + onKeyDown, +}) => { const [state, dispatch] = useReducer >(reducer, { activeRef: null, refs: [], @@ -166,6 +188,13 @@ export const RovingTabIndexProvider: React.FC = ({ children, handleHomeE const context = useMemo (() => ({ state, dispatch }), [state]); const onKeyDownHandler = useCallback((ev) => { + if (onKeyDown) { + onKeyDown(ev, context.state); + if (ev.defaultPrevented) { + return; + } + } + let handled = false; // Don't interfere with input default keydown behaviour if (ev.target.tagName !== "INPUT" && ev.target.tagName !== "TEXTAREA") { @@ -174,43 +203,37 @@ export const RovingTabIndexProvider: React.FC = ({ children, handleHomeE case Key.HOME: if (handleHomeEnd) { handled = true; - // move focus to first item - if (context.state.refs.length > 0) { - context.state.refs[0].current.focus(); - } + // move focus to first (visible) item + findSiblingElement(context.state.refs, 0)?.current?.focus(); } break; case Key.END: if (handleHomeEnd) { handled = true; - // move focus to last item - if (context.state.refs.length > 0) { - context.state.refs[context.state.refs.length - 1].current.focus(); - } + // move focus to last (visible) item + findSiblingElement(context.state.refs, context.state.refs.length - 1, true)?.current?.focus(); } break; case Key.ARROW_UP: - if (handleUpDown) { + case Key.ARROW_RIGHT: + if ((ev.key === Key.ARROW_UP && handleUpDown) || (ev.key === Key.ARROW_RIGHT && handleLeftRight)) { handled = true; if (context.state.refs.length > 0) { const idx = context.state.refs.indexOf(context.state.activeRef); - if (idx > 0) { - context.state.refs[idx - 1].current.focus(); - } + findSiblingElement(context.state.refs, idx - 1)?.current?.focus(); } } break; case Key.ARROW_DOWN: - if (handleUpDown) { + case Key.ARROW_LEFT: + if ((ev.key === Key.ARROW_DOWN && handleUpDown) || (ev.key === Key.ARROW_LEFT && handleLeftRight)) { handled = true; if (context.state.refs.length > 0) { const idx = context.state.refs.indexOf(context.state.activeRef); - if (idx < context.state.refs.length - 1) { - context.state.refs[idx + 1].current.focus(); - } + findSiblingElement(context.state.refs, idx + 1, true)?.current?.focus(); } } break; @@ -220,10 +243,8 @@ export const RovingTabIndexProvider: React.FC = ({ children, handleHomeE if (handled) { ev.preventDefault(); ev.stopPropagation(); - } else if (onKeyDown) { - return onKeyDown(ev, context.state); } - }, [context.state, onKeyDown, handleHomeEnd, handleUpDown]); + }, [context.state, onKeyDown, handleHomeEnd, handleUpDown, handleLeftRight]); return { children({ onKeyDownHandler }) } diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx index 90538760bb..6e99c7f1fa 100644 --- a/src/accessibility/Toolbar.tsx +++ b/src/accessibility/Toolbar.tsx @@ -16,7 +16,7 @@ limitations under the License. import React from "react"; -import { IState, RovingTabIndexProvider } from "./RovingTabIndex"; +import { RovingTabIndexProvider } from "./RovingTabIndex"; import { Key } from "../Keyboard"; interface IProps extends Omit , "onKeyDown"> { @@ -26,7 +26,7 @@ interface IProps extends Omit , "onKeyDown"> { // https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar // All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref` const Toolbar: React.FC = ({ children, ...props }) => { - const onKeyDown = (ev: React.KeyboardEvent, state: IState) => { + const onKeyDown = (ev: React.KeyboardEvent) => { const target = ev.target as HTMLElement; // Don't interfere with input default keydown behaviour if (target.tagName === "INPUT") return; @@ -42,15 +42,6 @@ const Toolbar: React.FC = ({ children, ...props }) => { } break; - case Key.ARROW_LEFT: - case Key.ARROW_RIGHT: - if (state.refs.length > 0) { - const i = state.refs.findIndex(r => r === state.activeRef); - const delta = ev.key === Key.ARROW_RIGHT ? 1 : -1; - state.refs.slice((i + delta) % state.refs.length)[0].current.focus(); - } - break; - default: handled = false; } diff --git a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx similarity index 67% rename from src/async-components/views/dialogs/security/CreateKeyBackupDialog.js rename to src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx index 9d449e8b80..c0aff7c8b9 100644 --- a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx @@ -17,56 +17,70 @@ limitations under the License. import React, { createRef } from 'react'; import FileSaver from 'file-saver'; -import PropTypes from 'prop-types'; -import { logger } from "matrix-js-sdk/src/logger"; - -import * as sdk from '../../../../index'; import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import { _t, _td } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../SecurityManager'; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; import { copyNode } from "../../../../utils/strings"; import PassphraseField from "../../../../components/views/auth/PassphraseField"; +import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps"; +import Field from "../../../../components/views/elements/Field"; +import Spinner from "../../../../components/views/elements/Spinner"; +import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; +import DialogButtons from "../../../../components/views/elements/DialogButtons"; +import { IValidationResult } from "../../../../components/views/elements/Validation"; +import { IPreparedKeyBackupVersion } from "matrix-js-sdk/src/crypto/backup"; +import { logger } from "matrix-js-sdk/src/logger"; -const PHASE_PASSPHRASE = 0; -const PHASE_PASSPHRASE_CONFIRM = 1; -const PHASE_SHOWKEY = 2; -const PHASE_KEEPITSAFE = 3; -const PHASE_BACKINGUP = 4; -const PHASE_DONE = 5; -const PHASE_OPTOUT_CONFIRM = 6; +enum Phase { + Passphrase = "passphrase", + PassphraseConfirm = "passphrase_confirm", + ShowKey = "show_key", + KeepItSafe = "keep_it_safe", + BackingUp = "backing_up", + Done = "done", + OptOutConfirm = "opt_out_confirm", +} const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc. +interface IProps extends IDialogProps {} + +interface IState { + secureSecretStorage: boolean; + phase: Phase; + passPhrase: string; + passPhraseValid: boolean; + passPhraseConfirm: string; + copied: boolean; + downloaded: boolean; + error?: string; +} + /* * Walks the user through the process of creating an e2e key backup * on the server. */ -export default class CreateKeyBackupDialog extends React.PureComponent { - static propTypes = { - onFinished: PropTypes.func.isRequired, - } +export default class CreateKeyBackupDialog extends React.PureComponent { + private keyBackupInfo: Pick ; + private recoveryKeyNode = createRef (); + private passphraseField = createRef (); - constructor(props) { + constructor(props: IProps) { super(props); - this._recoveryKeyNode = null; - this._keyBackupInfo = null; - this.state = { secureSecretStorage: null, - phase: PHASE_PASSPHRASE, + phase: Phase.Passphrase, passPhrase: '', passPhraseValid: false, passPhraseConfirm: '', copied: false, downloaded: false, }; - - this._passphraseField = createRef(); } - async componentDidMount() { + public async componentDidMount(): Promise { const cli = MatrixClientPeg.get(); const secureSecretStorage = await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing"); this.setState({ secureSecretStorage }); @@ -74,41 +88,37 @@ export default class CreateKeyBackupDialog extends React.PureComponent { // If we're using secret storage, skip ahead to the backing up step, as // `accessSecretStorage` will handle passphrases as needed. if (secureSecretStorage) { - this.setState({ phase: PHASE_BACKINGUP }); - this._createBackup(); + this.setState({ phase: Phase.BackingUp }); + this.createBackup(); } } - _collectRecoveryKeyNode = (n) => { - this._recoveryKeyNode = n; - } - - _onCopyClick = () => { - const successful = copyNode(this._recoveryKeyNode); + private onCopyClick = (): void => { + const successful = copyNode(this.recoveryKeyNode.current); if (successful) { this.setState({ copied: true, - phase: PHASE_KEEPITSAFE, + phase: Phase.KeepItSafe, }); } - } + }; - _onDownloadClick = () => { - const blob = new Blob([this._keyBackupInfo.recovery_key], { + private onDownloadClick = (): void => { + const blob = new Blob([this.keyBackupInfo.recovery_key], { type: 'text/plain;charset=us-ascii', }); FileSaver.saveAs(blob, 'security-key.txt'); this.setState({ downloaded: true, - phase: PHASE_KEEPITSAFE, + phase: Phase.KeepItSafe, }); - } + }; - _createBackup = async () => { + private createBackup = async (): Promise => { const { secureSecretStorage } = this.state; this.setState({ - phase: PHASE_BACKINGUP, + phase: Phase.BackingUp, error: null, }); let info; @@ -123,12 +133,12 @@ export default class CreateKeyBackupDialog extends React.PureComponent { }); } else { info = await MatrixClientPeg.get().createKeyBackupVersion( - this._keyBackupInfo, + this.keyBackupInfo, ); } await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup(); this.setState({ - phase: PHASE_DONE, + phase: Phase.Done, }); } catch (e) { logger.error("Error creating key backup", e); @@ -143,97 +153,91 @@ export default class CreateKeyBackupDialog extends React.PureComponent { error: e, }); } - } + }; - _onCancel = () => { + private onCancel = (): void => { this.props.onFinished(false); - } + }; - _onDone = () => { + private onDone = (): void => { this.props.onFinished(true); - } + }; - _onOptOutClick = () => { - this.setState({ phase: PHASE_OPTOUT_CONFIRM }); - } + private onSetUpClick = (): void => { + this.setState({ phase: Phase.Passphrase }); + }; - _onSetUpClick = () => { - this.setState({ phase: PHASE_PASSPHRASE }); - } - - _onSkipPassPhraseClick = async () => { - this._keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(); + private onSkipPassPhraseClick = async (): Promise => { + this.keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(); this.setState({ copied: false, downloaded: false, - phase: PHASE_SHOWKEY, + phase: Phase.ShowKey, }); - } + }; - _onPassPhraseNextClick = async (e) => { + private onPassPhraseNextClick = async (e: React.FormEvent): Promise => { e.preventDefault(); - if (!this._passphraseField.current) return; // unmounting + if (!this.passphraseField.current) return; // unmounting - await this._passphraseField.current.validate({ allowEmpty: false }); - if (!this._passphraseField.current.state.valid) { - this._passphraseField.current.focus(); - this._passphraseField.current.validate({ allowEmpty: false, focused: true }); + await this.passphraseField.current.validate({ allowEmpty: false }); + if (!this.passphraseField.current.state.valid) { + this.passphraseField.current.focus(); + this.passphraseField.current.validate({ allowEmpty: false, focused: true }); return; } - this.setState({ phase: PHASE_PASSPHRASE_CONFIRM }); + this.setState({ phase: Phase.PassphraseConfirm }); }; - _onPassPhraseConfirmNextClick = async (e) => { + private onPassPhraseConfirmNextClick = async (e: React.FormEvent): Promise => { e.preventDefault(); if (this.state.passPhrase !== this.state.passPhraseConfirm) return; - this._keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(this.state.passPhrase); + this.keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(this.state.passPhrase); this.setState({ copied: false, downloaded: false, - phase: PHASE_SHOWKEY, + phase: Phase.ShowKey, }); }; - _onSetAgainClick = () => { + private onSetAgainClick = (): void => { this.setState({ passPhrase: '', passPhraseValid: false, passPhraseConfirm: '', - phase: PHASE_PASSPHRASE, + phase: Phase.Passphrase, }); - } + }; - _onKeepItSafeBackClick = () => { + private onKeepItSafeBackClick = (): void => { this.setState({ - phase: PHASE_SHOWKEY, + phase: Phase.ShowKey, }); - } + }; - _onPassPhraseValidate = (result) => { + private onPassPhraseValidate = (result: IValidationResult): void => { this.setState({ passPhraseValid: result.valid, }); }; - _onPassPhraseChange = (e) => { + private onPassPhraseChange = (e: React.ChangeEvent ): void => { this.setState({ passPhrase: e.target.value, }); - } + }; - _onPassPhraseConfirmChange = (e) => { + private onPassPhraseConfirmChange = (e: React.ChangeEvent ): void => { this.setState({ passPhraseConfirm: e.target.value, }); - } + }; - _renderPhasePassPhrase() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return