From 1054d616818fdbacfb788d607ec34bc76b299b20 Mon Sep 17 00:00:00 2001 From: Thor Arne Johansen Date: Wed, 13 Mar 2024 14:29:19 +0100 Subject: [PATCH] Pull in develop branch which was synced from upstream (#10) * Upgrade dependency to matrix-js-sdk@31.5.0-rc.0 * v3.94.0-rc.0 * Handle up/down as well as left/right for horizontal toolbars for improved a11y (#12305) Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove references to internal js-sdk type `CryptoBackend` (#12321) * Remove references to internal js-sdk type `CryptoBackend` * Use `Paramteters` to avoid `ts-ignore` * Use `strong` element to semantically denote visually emphasised content (#12320) * Use `strong` element to semantically denote visually emphasised content Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add comment Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove unused slider component (#12303) It is unused as of https://github.com/matrix-org/matrix-react-sdk/pull/12246. I noticed this while working on https://github.com/matrix-org/matrix-react-sdk/pull/12299. * Update matrix-org (#11966) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update all non-major dependencies (#12322) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency stylelint-scss to v6.2.0 (#12323) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency @vector-im/compound-web to v3.1.3 (#12281) * Update dependency @vector-im/compound-web to v3.1.3 * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix TAC width due to compound update (#12326) --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Florian Duros * Call guest access link creation to join calls as a non registered user via the EC SPA (#12259) * Add externall call link button if in public call room Signed-off-by: Timo K * Allow configuring a spa homeserver url. Signed-off-by: Timo K * temp Signed-off-by: Timo K * remove homeserver url Signed-off-by: Timo K * Add custom title to share dialog. So that we can use it as a "share call" dialog. Signed-off-by: Timo K * - rename config options - only show link button if a guest url is provided - share dialog custom Title - rename call share labels Signed-off-by: Timo K * rename to title_link Signed-off-by: Timo K * add tests for ShareDialog Signed-off-by: Timo K * add tests for share call button Signed-off-by: Timo K * review Signed-off-by: Timo K * remove comment Signed-off-by: Timo K * Update src/components/views/dialogs/ShareDialog.tsx Co-authored-by: David Baker --------- Signed-off-by: Timo K Co-authored-by: David Baker * Fix spotlight opening in TAC (#12315) * Fix spotlight opening in TAC * Add tests * Remove `RovingTabIndexProvider` * Reset power selector on API failure to prevent state mismatch (#12319) * Reset power selector on API failure to prevent state mismatch Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Allow onChange to be sync or async Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add unmounted check Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Use correct push rule to evaluate room-wide mentions (#12318) Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve Forward Dialog a11y by switching to roving tab index interactions (#12306) * Improve Forward Dialog a11y by switching to roving tab index interactions Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve screen reader readout Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve screen reader readout Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * [create-pull-request] automated change (#12330) Co-authored-by: github-merge-queue * Reuse media content/info types from the js-sdk (#12308) * TAC: Fix CSS & component typos (#12333) * Fix CSS & component typo * Update snapshots * Element Call: fix widget shown while its still loading (`waitForIframeLoad=false`) (#12292) * show loading spinner also if waitForIframeLoad = false Configure EC so it waits for the content loaded action !WARNING This breaks compatibility with the full mesh branch. I would like to discuss here if/when we can do that. Signed-off-by: Timo K * stop show loading screen on widget ready (instead of preparing) Signed-off-by: Timo K * wait until widget loading is over before comparing screenshots Signed-off-by: Timo K * fix waitForIFrame=true widgets Signed-off-by: Timo K * test Signed-off-by: Timo K * always start with loading true. + cleanup Signed-off-by: Timo K * simplify loading Signed-off-by: Timo K * update snapshots (start not in loading state for waitForIframe = true widgets) Signed-off-by: Timo K --------- Signed-off-by: Timo K * Upgrade dependency to matrix-js-sdk@31.5.0 * v3.94.0 * Resetting package fields for development * Reset matrix-js-sdk back to develop branch --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> Signed-off-by: Timo K Co-authored-by: RiotRobot Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Robin Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Florian Duros Co-authored-by: Timo <16718859+toger5@users.noreply.github.com> Co-authored-by: David Baker Co-authored-by: github-merge-queue --- .eslintrc.js | 3 +- CHANGELOG.md | 22 + package.json | 2 +- .../threadsActivityCentre.spec.ts | 16 + res/css/_components.pcss | 1 - .../structures/_ThreadsActivityCentre.pcss | 10 +- res/css/views/dialogs/_ForwardDialog.pcss | 3 +- .../security/_AccessSecretStorageDialog.pcss | 2 + res/css/views/elements/_Slider.pcss | 126 ----- res/themes/dark/css/_dark.pcss | 2 - res/themes/legacy-dark/css/_legacy-dark.pcss | 3 - .../legacy-light/css/_legacy-light.pcss | 6 - .../css/_light-high-contrast.pcss | 5 - res/themes/light/css/_light.pcss | 2 - src/@types/matrix-js-sdk.d.ts | 27 + src/ContentMessages.ts | 18 +- src/IConfigOptions.ts | 1 + src/accessibility/RovingTabIndex.tsx | 20 +- src/accessibility/Toolbar.tsx | 3 +- .../security/NewRecoveryMethodDialog.tsx | 4 +- .../security/RecoveryMethodRemovedDialog.tsx | 2 +- src/components/structures/MatrixChat.tsx | 8 +- .../views/dialogs/ForwardDialog.tsx | 155 ++++-- src/components/views/dialogs/ShareDialog.tsx | 34 +- .../security/AccessSecretStorageDialog.tsx | 10 +- src/components/views/elements/AppTile.tsx | 13 +- .../views/elements/PowerSelector.tsx | 27 +- src/components/views/elements/Slider.tsx | 88 ---- .../views/elements/TruncatedList.tsx | 3 +- src/components/views/messages/MAudioBody.tsx | 4 +- src/components/views/messages/MFileBody.tsx | 6 +- src/components/views/messages/MImageBody.tsx | 2 +- .../views/messages/MImageReplyBody.tsx | 2 +- .../views/messages/MStickerBody.tsx | 4 +- src/components/views/messages/MVideoBody.tsx | 10 +- src/components/views/rooms/RoomHeader.tsx | 30 +- src/components/views/settings/SetIdServer.tsx | 4 +- .../tabs/room/RolesRoomSettingsTab.tsx | 22 +- .../tabs/user/MjolnirUserSettingsTab.tsx | 4 +- .../ThreadsActivityCentre.tsx | 83 +-- src/customisations/Media.ts | 7 +- .../models/IMediaEventContent.ts | 219 +------- src/hooks/room/useRoomCall.ts | 43 +- src/i18n/strings/en_EN.json | 4 + src/i18n/strings/eo.json | 1 + src/i18n/strings/et.json | 51 +- src/models/Call.ts | 2 +- src/models/RoomUpload.ts | 3 +- src/utils/DecryptFile.ts | 6 +- src/utils/FileUtils.ts | 6 +- src/utils/MediaEventHelper.ts | 6 +- src/utils/exportUtils/Exporter.ts | 4 +- src/utils/image-media.ts | 3 +- src/utils/pillify.tsx | 8 +- .../models/VoiceBroadcastRecording.ts | 2 +- test/accessibility/RovingTabIndex-test.tsx | 58 +++ .../__snapshots__/MessagePanel-test.tsx.snap | 2 +- .../__snapshots__/RoomView-test.tsx.snap | 14 +- .../SpaceHierarchy-test.tsx.snap | 8 +- .../__snapshots__/UserMenu-test.tsx.snap | 2 +- .../DecoratedRoomAvatar-test.tsx.snap | 4 +- .../__snapshots__/RoomAvatar-test.tsx.snap | 6 +- .../__snapshots__/BeaconMarker-test.tsx.snap | 2 +- .../BeaconViewDialog-test.tsx.snap | 2 +- .../__snapshots__/DialogSidebar-test.tsx.snap | 2 +- .../views/dialogs/ForwardDialog-test.tsx | 40 +- .../views/dialogs/ShareDialog-test.tsx | 130 +++++ .../ConfirmUserActionDialog-test.tsx.snap | 2 +- ...nageRestrictedJoinRuleDialog-test.tsx.snap | 2 +- .../views/elements/PowerSelector-test.tsx | 22 + .../__snapshots__/AppTile-test.tsx.snap | 18 +- .../__snapshots__/FacePile-test.tsx.snap | 4 +- .../elements/__snapshots__/Pill-test.tsx.snap | 16 +- .../__snapshots__/RoomFacePile-test.tsx.snap | 4 +- .../views/messages/TextualBody-test.tsx | 2 +- .../__snapshots__/MLocationBody-test.tsx.snap | 2 +- .../__snapshots__/TextualBody-test.tsx.snap | 20 +- .../RoomSummaryCard-test.tsx.snap | 104 ++-- .../__snapshots__/UserInfo-test.tsx.snap | 2 +- .../components/views/rooms/EventTile-test.tsx | 4 +- .../views/rooms/RoomHeader-test.tsx | 93 ++++ .../__snapshots__/MemberTile-test.tsx.snap | 6 +- .../PinnedEventTile-test.tsx.snap | 2 +- .../__snapshots__/RoomHeader-test.tsx.snap | 2 +- .../RoomPreviewBar-test.tsx.snap | 12 +- .../__snapshots__/RoomTile-test.tsx.snap | 8 +- .../tabs/room/RolesRoomSettingsTab-test.tsx | 38 +- .../PeopleRoomSettingsTab-test.tsx.snap | 6 +- .../MjolnirUserSettingsTab-test.tsx.snap | 8 +- .../spaces/ThreadsActivityCentre-test.tsx | 27 + .../AddExistingToSpaceDialog-test.tsx.snap | 4 +- .../ThreadsActivityCentre-test.tsx.snap | 32 +- test/test-utils/call.ts | 5 +- test/test-utils/test-utils.ts | 6 +- .../__snapshots__/HTMLExport-test.ts.snap | 6 +- test/utils/pillify-test.tsx | 50 +- .../models/VoiceBroadcastRecording-test.ts | 2 +- yarn.lock | 492 ++++++++---------- 98 files changed, 1352 insertions(+), 1071 deletions(-) delete mode 100644 res/css/views/elements/_Slider.pcss create mode 100644 src/@types/matrix-js-sdk.d.ts delete mode 100644 src/components/views/elements/Slider.tsx create mode 100644 test/components/views/dialogs/ShareDialog-test.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 342dbde484a..3beb4d2332f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -76,6 +76,7 @@ module.exports = { group: [ "matrix-js-sdk/src/**", "!matrix-js-sdk/src/matrix", + "!matrix-js-sdk/src/types", "matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**", @@ -125,8 +126,6 @@ module.exports = { "!matrix-js-sdk/src/crypto/verification/QRCode", "!matrix-js-sdk/src/crypto/verification/request", "!matrix-js-sdk/src/crypto/verification/request/VerificationRequest", - "!matrix-js-sdk/src/common-crypto", - "!matrix-js-sdk/src/common-crypto/CryptoBackend", "!matrix-js-sdk/src/oidc", "!matrix-js-sdk/src/oidc/discovery", "!matrix-js-sdk/src/oidc/authorize", diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bd5c61285a..563f34e1dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +Changes in [3.94.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.94.0) (2024-03-12) +===================================================================================================== +## ✨ Features + +* Refine styles of controls to match Compound ([#12299](https://github.com/matrix-org/matrix-react-sdk/pull/12299)). Contributed by @robintown. +* Hide the archived section ([#12286](https://github.com/matrix-org/matrix-react-sdk/pull/12286)). Contributed by @dbkr. +* Add theme data to EC widget Url ([#12279](https://github.com/matrix-org/matrix-react-sdk/pull/12279)). Contributed by @toger5. +* Update MSC2965 OIDC Discovery implementation ([#12245](https://github.com/matrix-org/matrix-react-sdk/pull/12245)). Contributed by @t3chguy. +* Use green dot for activity notification in `LegacyRoomHeader` ([#12270](https://github.com/matrix-org/matrix-react-sdk/pull/12270)). Contributed by @florianduros. + +## 🐛 Bug Fixes + +* Fix requests for senders to submit auto-rageshakes ([#12304](https://github.com/matrix-org/matrix-react-sdk/pull/12304)). Contributed by @richvdh. +* fix automatic DM avatar with functional members ([#12157](https://github.com/matrix-org/matrix-react-sdk/pull/12157)). Contributed by @HarHarLinks. +* Feeds event with relation to unknown to the widget ([#12283](https://github.com/matrix-org/matrix-react-sdk/pull/12283)). Contributed by @maheichyk. +* Fix TAC opening with keyboard ([#12285](https://github.com/matrix-org/matrix-react-sdk/pull/12285)). Contributed by @florianduros. +* Allow screenshot update docker to run multiple test files ([#12291](https://github.com/matrix-org/matrix-react-sdk/pull/12291)). Contributed by @dbkr. +* Fix alignment of user menu avatar ([#12289](https://github.com/matrix-org/matrix-react-sdk/pull/12289)). Contributed by @dbkr. +* Fix buttons of widget in a room ([#12288](https://github.com/matrix-org/matrix-react-sdk/pull/12288)). Contributed by @florianduros. +* ModuleAPI: `overwrite_login` action was not stopping the existing client resulting in the action failing with rust-sdk ([#12272](https://github.com/matrix-org/matrix-react-sdk/pull/12272)). Contributed by @BillCarsonFr. + + Changes in [3.93.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.93.0) (2024-02-27) ===================================================================================================== ## 🦖 Deprecations diff --git a/package.json b/package.json index 70e78efc1ca..36fc01ecb40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.93.0", + "version": "3.94.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { diff --git a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts index 1b237c0b534..eb4d7c8df06 100644 --- a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts +++ b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts @@ -17,6 +17,7 @@ */ import { expect, test } from "."; +import { CommandOrControl } from "../../utils"; test.describe("Threads Activity Centre", () => { test.use({ @@ -118,4 +119,19 @@ test.describe("Threads Activity Centre", () => { ]); await expect(util.getTacPanel()).toMatchScreenshot("tac-panel-notification-unread.png"); }); + + test("should block the Spotlight to open when the TAC is opened", async ({ util, page }) => { + const toggleSpotlight = () => page.keyboard.press(`${CommandOrControl}+k`); + + // Sanity check + // Open and close the spotlight + await toggleSpotlight(); + await expect(page.locator(".mx_SpotlightDialog")).toBeVisible(); + await toggleSpotlight(); + + await util.openTac(); + // The spotlight should not be opened + await toggleSpotlight(); + await expect(page.locator(".mx_SpotlightDialog")).not.toBeVisible(); + }); }); diff --git a/res/css/_components.pcss b/res/css/_components.pcss index a29e7e98570..1ae7648ca30 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -209,7 +209,6 @@ @import "./views/elements/_SearchWarning.pcss"; @import "./views/elements/_ServerPicker.pcss"; @import "./views/elements/_SettingsFlag.pcss"; -@import "./views/elements/_Slider.pcss"; @import "./views/elements/_Spinner.pcss"; @import "./views/elements/_StyledCheckbox.pcss"; @import "./views/elements/_StyledRadioButton.pcss"; diff --git a/res/css/structures/_ThreadsActivityCentre.pcss b/res/css/structures/_ThreadsActivityCentre.pcss index 7c597d95ea6..4c61d32f776 100644 --- a/res/css/structures/_ThreadsActivityCentre.pcss +++ b/res/css/structures/_ThreadsActivityCentre.pcss @@ -16,6 +16,10 @@ * / */ +.mx_ThreadsActivityCentre_container { + display: flex; +} + .mx_ThreadsActivityCentreButton { border-radius: 8px; margin: 18px auto auto auto; @@ -58,12 +62,12 @@ } } -.mx_ThreadsActivity_rows { +.mx_ThreadsActivityCentre_rows { overflow-y: scroll; /* Let some space at the top and the bottom of the pop-up */ max-height: calc(100vh - 200px); - .mx_ThreadsActivityRow { + .mx_ThreadsActivityCentreRow { height: 48px; /* Make the label of the MenuItem stay on one line and truncate with ellipsis if needed */ @@ -72,7 +76,7 @@ overflow: hidden; text-overflow: ellipsis; /* Arbitrary size, keep the TAC as the wanted width */ - width: 194px; + width: 202px; } } } diff --git a/res/css/views/dialogs/_ForwardDialog.pcss b/res/css/views/dialogs/_ForwardDialog.pcss index e6c322a77c6..69c9bafc89c 100644 --- a/res/css/views/dialogs/_ForwardDialog.pcss +++ b/res/css/views/dialogs/_ForwardDialog.pcss @@ -96,7 +96,8 @@ limitations under the License. padding: 6px; border-radius: 8px; - &:hover { + &:hover, + &.mx_ForwardList_entry_active { background-color: $spacePanel-bg-color; } diff --git a/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss b/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss index 85e5c082585..82e490c7817 100644 --- a/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss +++ b/res/css/views/dialogs/security/_AccessSecretStorageDialog.pcss @@ -117,6 +117,8 @@ limitations under the License. .mx_AccessSecretStorageDialog_reset { position: relative; padding-inline-start: $spacingStart; + /* To avoid bold styling inherent with elements */ + font-weight: inherit; &::before { content: ""; diff --git a/res/css/views/elements/_Slider.pcss b/res/css/views/elements/_Slider.pcss deleted file mode 100644 index 2477d542c64..00000000000 --- a/res/css/views/elements/_Slider.pcss +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -.mx_Slider { - position: relative; - margin: 0; - flex-grow: 1; - - input[type="range"] { - height: 2.4em; - appearance: none; - width: 100%; - background: none; - font-size: 1em; /* set base multiplier for em units applied later */ - - --active-color: var(--cpd-color-bg-action-primary-rest); - --selection-dot-size: 2.4em; - - &:disabled { - cursor: not-allowed; - - --active-color: $slider-background-color; - } - - &:focus:not(:focus-visible) { - outline: none; - } - - &::-webkit-slider-runnable-track { - width: 100%; - height: 0.4em; - background: $slider-background-color; - border-radius: 5px; - border: 0 solid #000000; - } - &::-webkit-slider-thumb { - border: 0 solid #000000; - width: var(--selection-dot-size); - height: var(--selection-dot-size); - background: var(--active-color); - border-radius: 50%; - -webkit-appearance: none; - margin-top: calc(2px + 1.2em - var(--selection-dot-size)); - } - &:focus::-webkit-slider-runnable-track { - background: $slider-background-color; - } - - &::-moz-range-track { - width: 100%; - height: 0.4em; - background: $slider-background-color; - border-radius: 5px; - border: 0 solid #000000; - } - &::-moz-range-progress { - height: 0.4em; - background: var(--active-color); - border-radius: 5px; - border: 0 solid #000000; - } - &::-moz-range-thumb { - border: 0 solid #000000; - width: var(--selection-dot-size); - height: var(--selection-dot-size); - background: var(--active-color); - border-radius: 50%; - } - - &::-ms-track { - width: 100%; - height: 0.4em; - background: transparent; - border-color: transparent; - color: transparent; - } - &::-ms-fill-lower, - &::-ms-fill-upper { - background: $slider-background-color; - border: 0 solid #000000; - border-radius: 10px; - } - &::-ms-thumb { - margin-top: 1px; - width: var(--selection-dot-size); - height: var(--selection-dot-size); - background: var(--active-color); - border-radius: 50%; - } - &:focus::-ms-fill-upper { - background: $slider-background-color; - } - &::-ms-fill-lower, - &:focus::-ms-fill-lower { - background: var(--active-color); - } - } - - output { - position: absolute; - left: 50%; - transform: translateX(-50%); - - font-size: 1em; /* set base multiplier for em units applied later */ - text-align: center; - top: 3em; - - .mx_Slider_selection_label { - color: $muted-fg-color; - font: var(--cpd-font-body-md-regular); - } - } -} diff --git a/res/themes/dark/css/_dark.pcss b/res/themes/dark/css/_dark.pcss index eb37ab743a1..f7c9a61c336 100644 --- a/res/themes/dark/css/_dark.pcss +++ b/res/themes/dark/css/_dark.pcss @@ -251,8 +251,6 @@ $progressbar-bg-color: var(--cpd-color-gray-200); $kbd-border-color: $strong-input-border-color; $visual-bell-bg-color: #800; $event-timestamp-color: $text-secondary-color; -$slider-background-color: $quinary-content; -$appearance-tab-border-color: $room-highlight-color; $composer-shadow-color: rgba(0, 0, 0, 0.28); $breadcrumb-placeholder-bg-color: #272c35; $theme-button-bg-color: #e3e8f0; diff --git a/res/themes/legacy-dark/css/_legacy-dark.pcss b/res/themes/legacy-dark/css/_legacy-dark.pcss index d9db8465831..c1bf80310ad 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.pcss +++ b/res/themes/legacy-dark/css/_legacy-dark.pcss @@ -208,9 +208,6 @@ $breadcrumb-placeholder-bg-color: #272c35; $voice-record-stop-border-color: #6f7882; $voice-record-icon-color: #6f7882; -/* Appearance tab colors */ -$appearance-tab-border-color: $room-highlight-color; - $composer-shadow-color: tranparent; $codeblock-background-color: #2a3039; diff --git a/res/themes/legacy-light/css/_legacy-light.pcss b/res/themes/legacy-light/css/_legacy-light.pcss index 290027e5841..f277e07d8ca 100644 --- a/res/themes/legacy-light/css/_legacy-light.pcss +++ b/res/themes/legacy-light/css/_legacy-light.pcss @@ -269,9 +269,6 @@ $visual-bell-bg-color: #faa; $togglesw-off-color: #c1c9d6; $togglesw-ball-color: var(--cpd-color-bg-action-primary-rest); -/* Slider */ -$slider-background-color: #c1c9d6; - $progressbar-bg-color: rgba(141, 151, 165, 0.2); $authpage-bg-color: #2e3649; @@ -305,9 +302,6 @@ $voice-record-live-circle-color: #ff4b55; $voice-record-stop-border-color: #e3e8f0; $voice-record-icon-color: $tertiary-fg-color; -/* FontSlider colors */ -$appearance-tab-border-color: $input-darker-bg-color; - $composer-shadow-color: tranparent; $codeblock-background-color: $header-panel-bg-color; diff --git a/res/themes/light-high-contrast/css/_light-high-contrast.pcss b/res/themes/light-high-contrast/css/_light-high-contrast.pcss index 396b4946996..6bfd5b8fd4f 100644 --- a/res/themes/light-high-contrast/css/_light-high-contrast.pcss +++ b/res/themes/light-high-contrast/css/_light-high-contrast.pcss @@ -31,7 +31,6 @@ $button-secondary-bg-color: $accent-fg-color; $message-action-bar-fg-color: $primary-content; $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; $roomtopic-color: $secondary-content; @@ -104,10 +103,6 @@ $accent-1400: var(--cpd-color-green-1400); background-color: $panel-actions !important; } -.mx_FontScalingPanel_fontSlider { - background-color: $panel-actions !important; -} - .mx_ThemeChoicePanel_themeSelectors > .mx_StyledRadioButton input[type="radio"]:disabled + div { border-color: $primary-content; } diff --git a/res/themes/light/css/_light.pcss b/res/themes/light/css/_light.pcss index a201adbc44f..ee48dc80476 100644 --- a/res/themes/light/css/_light.pcss +++ b/res/themes/light/css/_light.pcss @@ -316,8 +316,6 @@ $progressbar-bg-color: var(--cpd-color-gray-200); $kbd-border-color: $strong-input-border-color; $visual-bell-bg-color: #faa; $event-timestamp-color: #acacac; -$slider-background-color: $togglesw-off-color; -$appearance-tab-border-color: $input-darker-bg-color; $composer-shadow-color: rgba(0, 0, 0, 0.04); $breadcrumb-placeholder-bg-color: #e8eef5; $theme-button-bg-color: $quinary-content; diff --git a/src/@types/matrix-js-sdk.d.ts b/src/@types/matrix-js-sdk.d.ts new file mode 100644 index 00000000000..1ce1702f1fb --- /dev/null +++ b/src/@types/matrix-js-sdk.d.ts @@ -0,0 +1,27 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +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 { BLURHASH_FIELD } from "../utils/image-media"; + +// Matrix JS SDK extensions +declare module "matrix-js-sdk" { + export interface FileInfo { + /** + * @see https://github.com/matrix-org/matrix-spec-proposals/pull/2448 + */ + [BLURHASH_FIELD]?: string; + } +} diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index 9a8a1d7c4fb..0a5198ea567 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -28,19 +28,19 @@ import { UploadProgress, THREAD_RELATION_TYPE, } from "matrix-js-sdk/src/matrix"; +import { + ImageInfo, + AudioInfo, + VideoInfo, + EncryptedFile, + MediaEventContent, + MediaEventInfo, +} from "matrix-js-sdk/src/types"; import encrypt from "matrix-encrypt-attachment"; import extractPngChunks from "png-chunks-extract"; import { logger } from "matrix-js-sdk/src/logger"; import { removeElement } from "matrix-js-sdk/src/utils"; -import { - AudioInfo, - EncryptedFile, - ImageInfo, - IMediaEventContent, - IMediaEventInfo, - VideoInfo, -} from "./customisations/models/IMediaEventContent"; import dis from "./dispatcher/dispatcher"; import { _t } from "./languageHandler"; import Modal from "./Modal"; @@ -537,7 +537,7 @@ export default class ContentMessages { promBefore?: Promise, ): Promise { const fileName = file.name || _t("common|attachment"); - const content: Omit & { info: Partial } = { + const content: Omit & { info: Partial } = { body: fileName, info: { size: file.size, diff --git a/src/IConfigOptions.ts b/src/IConfigOptions.ts index 501d8a3bd64..4dc537aab07 100644 --- a/src/IConfigOptions.ts +++ b/src/IConfigOptions.ts @@ -119,6 +119,7 @@ export interface IConfigOptions { }; element_call: { url?: string; + guest_spa_url?: string; use_exclusively?: boolean; participant_limit?: number; brand?: string; diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx index 5f3901a3916..9a2a8552423 100644 --- a/src/accessibility/RovingTabIndex.tsx +++ b/src/accessibility/RovingTabIndex.tsx @@ -175,6 +175,8 @@ interface IProps { handleHomeEnd?: boolean; handleUpDown?: boolean; handleLeftRight?: boolean; + handleInputFields?: boolean; + scrollIntoView?: boolean | ScrollIntoViewOptions; children(renderProps: { onKeyDownHandler(ev: React.KeyboardEvent): void; onDragEndHandler(): void }): ReactNode; onKeyDown?(ev: React.KeyboardEvent, state: IState, dispatch: Dispatch): void; } @@ -212,6 +214,8 @@ export const RovingTabIndexProvider: React.FC = ({ handleUpDown, handleLeftRight, handleLoop, + handleInputFields, + scrollIntoView, onKeyDown, }) => { const [state, dispatch] = useReducer>(reducer, { @@ -234,7 +238,7 @@ export const RovingTabIndexProvider: React.FC = ({ let focusRef: RefObject | undefined; // Don't interfere with input default keydown behaviour // but allow people to move focus from it with Tab. - if (checkInputableElement(ev.target as HTMLElement)) { + if (!handleInputFields && checkInputableElement(ev.target as HTMLElement)) { switch (action) { case KeyBindingAction.Tab: handled = true; @@ -311,9 +315,21 @@ export const RovingTabIndexProvider: React.FC = ({ ref: focusRef, }, }); + if (scrollIntoView) { + focusRef.current?.scrollIntoView(scrollIntoView); + } } }, - [context, onKeyDown, handleHomeEnd, handleUpDown, handleLeftRight, handleLoop], + [ + context, + onKeyDown, + handleHomeEnd, + handleUpDown, + handleLeftRight, + handleLoop, + handleInputFields, + scrollIntoView, + ], ); const onDragEndHandler = useCallback(() => { diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx index a606f9aae89..c5a81aeda34 100644 --- a/src/accessibility/Toolbar.tsx +++ b/src/accessibility/Toolbar.tsx @@ -53,8 +53,9 @@ const Toolbar = forwardRef(({ children, ...props }, ref) } }; + // We handle both up/down and left/right as is allowed in the above WAI ARIA best practices return ( - + {({ onKeyDownHandler }) => (
{children} diff --git a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx index 95aab12e45c..0778879976c 100644 --- a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx +++ b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx @@ -63,7 +63,9 @@ export default class NewRecoveryMethodDialog extends React.PureComponent const newMethodDetected =

{_t("encryption|new_recovery_method_detected|description_1")}

; - const hackWarning =

{_t("encryption|new_recovery_method_detected|warning")}

; + const hackWarning = ( + {_t("encryption|new_recovery_method_detected|warning")} + ); let content: JSX.Element | undefined; if (MatrixClientPeg.safeGet().getKeyBackupEnabled()) { diff --git a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx index 4dafcfa5182..c864eb1abba 100644 --- a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx +++ b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx @@ -55,7 +55,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent

{_t("encryption|recovery_method_removed|description_1")}

{_t("encryption|recovery_method_removed|description_2")}

-

{_t("encryption|recovery_method_removed|warning")}

+ {_t("encryption|recovery_method_removed|warning")} { const memberCount = roomToLeave?.currentState.getJoinedMemberCount(); if (memberCount === 1) { warnings.push( - + {" " /* Whitespace, otherwise the sentences get smashed together */} {_t("leave_room_dialog|last_person_warning")} - , + , ); return warnings; @@ -1193,12 +1193,12 @@ export default class MatrixChat extends React.PureComponent { const rule = joinRules.getContent().join_rule; if (rule !== "public") { warnings.push( - + {" " /* Whitespace, otherwise the sentences get smashed together */} {isSpace ? _t("leave_room_dialog|space_rejoin_warning") : _t("leave_room_dialog|room_rejoin_warning")} - , + , ); } } diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index a21acd7b717..fe737386295 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -57,6 +57,15 @@ import { isLocationEvent } from "../../../utils/EventUtils"; import { isSelfLocation, locationEventGeoUri } from "../../../utils/location"; import { RoomContextDetails } from "../rooms/RoomContextDetails"; import { filterBoolean } from "../../../utils/arrays"; +import { + IState, + RovingTabIndexContext, + RovingTabIndexProvider, + Type, + useRovingTabIndex, +} from "../../../accessibility/RovingTabIndex"; +import { getKeyBindingsManager } from "../../../KeyBindingsManager"; +import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; const AVATAR_SIZE = 30; @@ -87,6 +96,7 @@ enum SendState { const Entry: React.FC = ({ room, type, content, matrixClient: cli, onFinished }) => { const [sendState, setSendState] = useState(SendState.CanSend); + const [onFocus, isActive, ref] = useRovingTabIndex(); const jumpToRoom = (ev: ButtonEvent): void => { dis.dispatch({ @@ -134,16 +144,30 @@ const Entry: React.FC = ({ room, type, content, matrixClient: cli, icon = ; } + const id = `mx_ForwardDialog_entry_${room.roomId}`; return ( -
+
- - {room.name} + + + {room.name} + = ({ room, type, content, matrixClient: cli, disabled={disabled} title={title} alignment={Alignment.Top} + tabIndex={isActive ? 0 : -1} + id={`${id}_send`} >
{_t("forward|send_label")}
{icon} @@ -270,6 +296,26 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr ); } + const onKeyDown = (ev: React.KeyboardEvent, state: IState): void => { + let handled = true; + + const action = getKeyBindingsManager().getAccessibilityAction(ev); + switch (action) { + case KeyBindingAction.Enter: { + state.activeRef?.current?.querySelector(".mx_ForwardList_sendButton")?.click(); + break; + } + + default: + handled = false; + } + + if (handled) { + ev.preventDefault(); + ev.stopPropagation(); + } + }; + return ( = ({ matrixClient: cli, event, permalinkCr />

-
- - - {rooms.length > 0 ? ( -
- - rooms - .slice(start, end) - .map((room) => ( - - )) - } - getChildCount={() => rooms.length} - /> -
- ) : ( - {_t("common|no_results")} - )} -
-
+ + {({ onKeyDownHandler }) => ( +
+ + {(context) => ( + { + setQuery(query); + setImmediate(() => { + const ref = context.state.refs[0]; + if (ref) { + context.dispatch({ + type: Type.SetFocus, + payload: { ref }, + }); + ref.current?.scrollIntoView?.({ + block: "nearest", + }); + } + }); + }} + autoFocus={true} + onKeyDown={onKeyDownHandler} + aria-activedescendant={context.state.activeRef?.current?.id} + aria-owns="mx_ForwardDialog_resultsList" + /> + )} + + + {rooms.length > 0 ? ( +
+ + rooms + .slice(start, end) + .map((room) => ( + + )) + } + getChildCount={() => rooms.length} + /> +
+ ) : ( + {_t("common|no_results")} + )} +
+
+ )} +
); }; diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx index aba35e70e2c..9e6ee7fc8aa 100644 --- a/src/components/views/dialogs/ShareDialog.tsx +++ b/src/components/views/dialogs/ShareDialog.tsx @@ -62,11 +62,28 @@ const socials = [ ]; interface BaseProps { + /** + * A function that is called when the dialog is dismissed + */ onFinished(): void; + /** + * An optional string to use as the dialog title. + * If not provided, an appropriate title for the target type will be used. + */ + customTitle?: string; + /** + * An optional string to use as the dialog subtitle + */ + subtitle?: string; } interface Props extends BaseProps { - target: Room | User | RoomMember; + /** + * The target to link to. + * This can be a Room, User, RoomMember, or MatrixEvent or an already computed URL. + * A matrix.to link will be generated out of it if it's not already a url. + */ + target: Room | User | RoomMember | URL; permalinkCreator?: RoomPermalinkCreator; } @@ -109,7 +126,9 @@ export default class ShareDialog extends React.PureComponent 0) { @@ -146,9 +167,9 @@ export default class ShareDialog extends React.PureComponent + {this.props.subtitle &&

{this.props.subtitle}

} + ); let content; @@ -366,7 +366,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent
@@ -434,7 +434,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent
diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 74317041bd2..34c773d3c94 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -249,8 +249,9 @@ export default class AppTile extends React.Component { private getNewState(newProps: IProps): IState { return { initialising: true, // True while we are mangling the widget URL - // True while the iframe content is loading - loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this.persistKey), + // Don't show loading at all if the widget is ready once the IFrame is loaded (waitForIframeLoad = true). + // We only need the loading screen if the widget sends a contentLoaded event (waitForIframeLoad = false). + loading: !this.props.waitForIframeLoad && !PersistedElement.isMounted(this.persistKey), // Assume that widget has permission to load if we are the user who // added it to the room, or if explicitly granted by the user hasPermissionToLoad: this.hasPermissionToLoad(newProps), @@ -312,7 +313,6 @@ export default class AppTile extends React.Component { if (this.props.room) { this.context.on(RoomEvent.MyMembership, this.onMyMembership); } - this.allowedWidgetsWatchRef = SettingsStore.watchSetting("allowedWidgets", null, this.onAllowedWidgetsChange); // Widget action listeners this.dispatcherRef = dis.register(this.onAction); @@ -352,7 +352,7 @@ export default class AppTile extends React.Component { } private setupSgListeners(): void { - this.sgWidget?.on("preparing", this.onWidgetPreparing); + this.sgWidget?.on("ready", this.onWidgetReady); this.sgWidget?.on("error:preparing", this.updateRequiresClient); // emits when the capabilities have been set up or changed this.sgWidget?.on("capabilitiesNotified", this.updateRequiresClient); @@ -360,7 +360,7 @@ export default class AppTile extends React.Component { private stopSgListeners(): void { if (!this.sgWidget) return; - this.sgWidget.off("preparing", this.onWidgetPreparing); + this.sgWidget?.off("ready", this.onWidgetReady); this.sgWidget.off("error:preparing", this.updateRequiresClient); this.sgWidget.off("capabilitiesNotified", this.updateRequiresClient); } @@ -446,8 +446,7 @@ export default class AppTile extends React.Component { this.sgWidget?.stopMessaging({ forceDestroy: true }); } - - private onWidgetPreparing = (): void => { + private onWidgetReady = (): void => { this.setState({ loading: false }); }; diff --git a/src/components/views/elements/PowerSelector.tsx b/src/components/views/elements/PowerSelector.tsx index 36bb51e4bbe..7dcf3d78ecc 100644 --- a/src/components/views/elements/PowerSelector.tsx +++ b/src/components/views/elements/PowerSelector.tsx @@ -39,7 +39,7 @@ interface Props { // The name to annotate the selector with label?: string; - onChange(value: number, powerLevelKey: K extends undefined ? void : K): void; + onChange(value: number, powerLevelKey: K extends undefined ? void : K): void | Promise; // Optional key to pass as the second argument to `onChange` powerLevelKey: K extends undefined ? void : K; @@ -60,6 +60,7 @@ export default class PowerSelector extends React.C maxValue: Infinity, usersDefault: 0, }; + private unmounted = false; public constructor(props: Props) { super(props); @@ -84,6 +85,10 @@ export default class PowerSelector extends React.C } } + public componentWillUnmount(): void { + this.unmounted = true; + } + private initStateFromProps(): void { // This needs to be done now because levelRoleMap has translated strings const levelRoleMap = Roles.levelRoleMap(this.props.usersDefault); @@ -106,14 +111,20 @@ export default class PowerSelector extends React.C }); } - private onSelectChange = (event: React.ChangeEvent): void => { + private onSelectChange = async (event: React.ChangeEvent): Promise => { const isCustom = event.target.value === CUSTOM_VALUE; if (isCustom) { this.setState({ custom: true }); } else { const powerLevel = parseInt(event.target.value); - this.props.onChange(powerLevel, this.props.powerLevelKey); this.setState({ selectValue: powerLevel }); + try { + await this.props.onChange(powerLevel, this.props.powerLevelKey); + } catch { + if (this.unmounted) return; + // If the request failed, roll back the state of the selector. + this.initStateFromProps(); + } } }; @@ -121,12 +132,18 @@ export default class PowerSelector extends React.C this.setState({ customValue: parseInt(event.target.value) }); }; - private onCustomBlur = (event: React.FocusEvent): void => { + private onCustomBlur = async (event: React.FocusEvent): Promise => { event.preventDefault(); event.stopPropagation(); if (Number.isFinite(this.state.customValue)) { - this.props.onChange(this.state.customValue, this.props.powerLevelKey); + try { + await this.props.onChange(this.state.customValue, this.props.powerLevelKey); + } catch { + if (this.unmounted) return; + // If the request failed, roll back the state of the selector. + this.initStateFromProps(); + } } else { this.initStateFromProps(); // reset, invalid input } diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx deleted file mode 100644 index 44947aa6518..00000000000 --- a/src/components/views/elements/Slider.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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 * as React from "react"; -import { ChangeEvent } from "react"; - -interface IProps { - // A callback for the selected value - onChange: (value: number) => void; - - // The current value of the slider - value: number; - - // The min and max of the slider - min: number; - max: number; - // The step size of the slider, can be a number or "any" - step: number | "any"; - - // A function for formatting the values - displayFunc: (value: number) => string; - - // Whether the slider is disabled - disabled: boolean; - - label: string; -} - -const THUMB_SIZE = 2.4; // em - -export default class Slider extends React.Component { - private get position(): number { - const { min, max, value } = this.props; - return Number(((value - min) * 100) / (max - min)); - } - - private onChange = (ev: ChangeEvent): void => { - this.props.onChange(parseInt(ev.target.value, 10)); - }; - - public render(): React.ReactNode { - let selection: JSX.Element | undefined; - - if (!this.props.disabled) { - const position = this.position; - selection = ( - - {this.props.value} - - ); - } - - return ( -
- - {selection} -
- ); - } -} diff --git a/src/components/views/elements/TruncatedList.tsx b/src/components/views/elements/TruncatedList.tsx index 074df5bfb26..4c6979832d2 100644 --- a/src/components/views/elements/TruncatedList.tsx +++ b/src/components/views/elements/TruncatedList.tsx @@ -36,6 +36,7 @@ interface IProps { // This will be inserted after the children. createOverflowElement: (overflowCount: number, totalCount: number) => React.ReactNode; children?: ReactNode; + id?: string; } export default class TruncatedList extends React.Component { @@ -86,7 +87,7 @@ export default class TruncatedList extends React.Component { const childNodes = this.getChildren(0, upperBound); return ( -
+
{childNodes} {overflowNode}
diff --git a/src/components/views/messages/MAudioBody.tsx b/src/components/views/messages/MAudioBody.tsx index 52cd2334afd..de30b65f724 100644 --- a/src/components/views/messages/MAudioBody.tsx +++ b/src/components/views/messages/MAudioBody.tsx @@ -17,12 +17,12 @@ limitations under the License. import React from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { IContent } from "matrix-js-sdk/src/matrix"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import { Playback } from "../../../audio/Playback"; import InlineSpinner from "../elements/InlineSpinner"; import { _t } from "../../../languageHandler"; import AudioPlayer from "../audio_messages/AudioPlayer"; -import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; import MFileBody from "./MFileBody"; import { IBodyProps } from "./IBodyProps"; import { PlaybackManager } from "../../../audio/PlaybackManager"; @@ -67,7 +67,7 @@ export default class MAudioBody extends React.PureComponent // We should have a buffer to work with now: let's set it up // Note: we don't actually need a waveform to render an audio event, but voice messages do. - const content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); const waveform = content?.["org.matrix.msc1767.audio"]?.waveform?.map((p: number) => p / 1024); // We should have a buffer to work with now: let's set it up diff --git a/src/components/views/messages/MFileBody.tsx b/src/components/views/messages/MFileBody.tsx index ab0c1f505ec..12d4c804168 100644 --- a/src/components/views/messages/MFileBody.tsx +++ b/src/components/views/messages/MFileBody.tsx @@ -16,6 +16,7 @@ limitations under the License. import React, { AllHTMLAttributes, createRef } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; @@ -23,7 +24,6 @@ import AccessibleButton from "../elements/AccessibleButton"; import { mediaFromContent } from "../../../customisations/Media"; import ErrorDialog from "../dialogs/ErrorDialog"; import { fileSize, presentableTextForFile } from "../../../utils/FileUtils"; -import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; import { IBodyProps } from "./IBodyProps"; import { FileDownloader } from "../../../utils/FileDownloader"; import TextWithTooltip from "../elements/TextWithTooltip"; @@ -128,8 +128,8 @@ export default class MFileBody extends React.Component { const media = mediaFromContent(this.props.mxEvent.getContent()); return media.srcHttp; } - private get content(): IMediaEventContent { - return this.props.mxEvent.getContent(); + private get content(): MediaEventContent { + return this.props.mxEvent.getContent(); } private get fileName(): string { diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx index ff4d573e059..36f3a851687 100644 --- a/src/components/views/messages/MImageBody.tsx +++ b/src/components/views/messages/MImageBody.tsx @@ -21,6 +21,7 @@ import classNames from "classnames"; import { CSSTransition, SwitchTransition } from "react-transition-group"; import { logger } from "matrix-js-sdk/src/logger"; import { ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix"; +import { ImageContent } from "matrix-js-sdk/src/types"; import { Tooltip } from "@vector-im/compound-web"; import MFileBody from "./MFileBody"; @@ -30,7 +31,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import Spinner from "../elements/Spinner"; import { Media, mediaFromContent } from "../../../customisations/Media"; import { BLURHASH_FIELD, createThumbnail } from "../../../utils/image-media"; -import { ImageContent } from "../../../customisations/models/IMediaEventContent"; import ImageView from "../elements/ImageView"; import { IBodyProps } from "./IBodyProps"; import { ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize"; diff --git a/src/components/views/messages/MImageReplyBody.tsx b/src/components/views/messages/MImageReplyBody.tsx index c6d61a7ba5b..ded0d374a80 100644 --- a/src/components/views/messages/MImageReplyBody.tsx +++ b/src/components/views/messages/MImageReplyBody.tsx @@ -15,9 +15,9 @@ limitations under the License. */ import React from "react"; +import { ImageContent } from "matrix-js-sdk/src/types"; import MImageBody from "./MImageBody"; -import { ImageContent } from "../../../customisations/models/IMediaEventContent"; const FORCED_IMAGE_HEIGHT = 44; diff --git a/src/components/views/messages/MStickerBody.tsx b/src/components/views/messages/MStickerBody.tsx index 26c33e89fca..a002670b52b 100644 --- a/src/components/views/messages/MStickerBody.tsx +++ b/src/components/views/messages/MStickerBody.tsx @@ -16,10 +16,10 @@ limitations under the License. import React, { ComponentProps, ReactNode } from "react"; import { Tooltip } from "@vector-im/compound-web"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import MImageBody from "./MImageBody"; import { BLURHASH_FIELD } from "../../../utils/image-media"; -import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; export default class MStickerBody extends MImageBody { // Mostly empty to prevent default behaviour of MImageBody @@ -80,7 +80,7 @@ export default class MStickerBody extends MImageBody { return null; } - protected getBanner(content: IMediaEventContent): ReactNode { + protected getBanner(content: MediaEventContent): ReactNode { return null; // we don't need a banner, we have a tooltip } } diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index df3ab6abbf9..be6ae4442ce 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -16,6 +16,7 @@ limitations under the License. import React, { ReactNode } from "react"; import { decode } from "blurhash"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../languageHandler"; @@ -23,7 +24,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import InlineSpinner from "../elements/InlineSpinner"; import { mediaFromContent } from "../../../customisations/Media"; import { BLURHASH_FIELD } from "../../../utils/image-media"; -import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; import { IBodyProps } from "./IBodyProps"; import MFileBody from "./MFileBody"; import { ImageSize, suggestedSize as suggestedVideoSize } from "../../../settings/enums/ImageSize"; @@ -62,7 +62,7 @@ export default class MVideoBody extends React.PureComponent } private getContentUrl(): string | undefined { - const content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); // During export, the content url will point to the MSC, which will later point to a local url if (this.props.forExport) return content.file?.url ?? content.url; const media = mediaFromContent(content); @@ -82,7 +82,7 @@ export default class MVideoBody extends React.PureComponent // there's no need of thumbnail when the content is local if (this.props.forExport) return null; - const content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); const media = mediaFromContent(content); if (media.isEncrypted && this.state.decryptedThumbnailUrl) { @@ -121,7 +121,7 @@ export default class MVideoBody extends React.PureComponent posterLoading: true, }); - const content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); const media = mediaFromContent(content); if (media.hasThumbnail) { const image = new Image(); @@ -157,7 +157,7 @@ export default class MVideoBody extends React.PureComponent this.props.onHeightChanged?.(); } else { logger.log("NOT preloading video"); - const content = this.props.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); let mimetype = content?.info?.mimetype; diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx index 6d1ea9f8eb6..8ca26ebcdea 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -18,6 +18,7 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Body as BodyText, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web"; import { Icon as VideoCallIcon } from "@vector-im/compound-design-tokens/icons/video-call-solid.svg"; import { Icon as VoiceCallIcon } from "@vector-im/compound-design-tokens/icons/voice-call.svg"; +import { Icon as ExternalLinkIcon } from "@vector-im/compound-design-tokens/icons/link.svg"; import { Icon as CloseCallIcon } from "@vector-im/compound-design-tokens/icons/close.svg"; import { Icon as ThreadsIcon } from "@vector-im/compound-design-tokens/icons/threads-solid.svg"; import { Icon as NotificationsIcon } from "@vector-im/compound-design-tokens/icons/notifications-solid.svg"; @@ -26,6 +27,7 @@ import { Icon as ErrorIcon } from "@vector-im/compound-design-tokens/icons/error import { Icon as PublicIcon } from "@vector-im/compound-design-tokens/icons/public.svg"; import { EventType, JoinRule, type Room } from "matrix-js-sdk/src/matrix"; import { ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle"; +import { logger } from "matrix-js-sdk/src/logger"; import { useRoomName } from "../../../hooks/useRoomName"; import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases"; @@ -54,6 +56,8 @@ import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton"; import { RoomKnocksBar } from "./RoomKnocksBar"; import { isVideoRoom } from "../../../utils/video-rooms"; import { notificationLevelToIndicator } from "../../../utils/notifications"; +import Modal from "../../../Modal"; +import ShareDialog from "../dialogs/ShareDialog"; export default function RoomHeader({ room, @@ -78,6 +82,8 @@ export default function RoomHeader({ videoCallClick, toggleCallMaximized: toggleCall, isViewingCall, + generateCallLink, + canGenerateCallLink, isConnectedToCall, hasActiveCallSession, callOptions, @@ -118,6 +124,20 @@ export default function RoomHeader({ const videoClick = useCallback((ev) => videoCallClick(ev, callOptions[0]), [callOptions, videoCallClick]); + const shareClick = useCallback(() => { + try { + // generateCallLink throws if the permissions are not met + const target = generateCallLink(); + Modal.createDialog(ShareDialog, { + target, + customTitle: _t("share|share_call"), + subtitle: _t("share|share_call_subtitle"), + }); + } catch (e) { + logger.error("Could not generate call link.", e); + } + }, [generateCallLink]); + const toggleCallButton = ( @@ -125,7 +145,13 @@ export default function RoomHeader({ ); - + const createExternalLinkButton = ( + + + + + + ); const joinCallButton = (
); } else if (this.state.error) { - return {this.state.error}; + return {this.state.error}; } else { return null; } @@ -226,7 +226,7 @@ export default class SetIdServer extends React.Component { title: _t("terms|identity_server_no_terms_title"), description: (
- {_t("identity_server|no_terms")} + {_t("identity_server|no_terms")}  {_t("terms|identity_server_no_terms_description_2")}
), diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx index 7bce2ccb17f..5f03e7f9505 100644 --- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx @@ -174,7 +174,7 @@ export default class RolesRoomSettingsTab extends React.Component { } } - private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => { + private onPowerLevelsChanged = async (value: number, powerLevelKey: string): Promise => { const client = this.context; const room = this.props.room; const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); @@ -203,17 +203,22 @@ export default class RolesRoomSettingsTab extends React.Component { parentObj[keyPath[keyPath.length - 1]] = value; } - client.sendStateEvent(this.props.room.roomId, EventType.RoomPowerLevels, plContent).catch((e) => { + try { + await client.sendStateEvent(this.props.room.roomId, EventType.RoomPowerLevels, plContent); + } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("room_settings|permissions|error_changing_pl_reqs_title"), description: _t("room_settings|permissions|error_changing_pl_reqs_description"), }); - }); + + // Rethrow so that the PowerSelector can roll back + throw e; + } }; - private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => { + private onUserPowerLevelChanged = async (value: number, powerLevelKey: string): Promise => { const client = this.context; const room = this.props.room; const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); @@ -226,14 +231,19 @@ export default class RolesRoomSettingsTab extends React.Component { if (!plContent["users"]) plContent["users"] = {}; plContent["users"][powerLevelKey] = value; - client.sendStateEvent(this.props.room.roomId, EventType.RoomPowerLevels, plContent).catch((e) => { + try { + await client.sendStateEvent(this.props.room.roomId, EventType.RoomPowerLevels, plContent); + } catch (e) { logger.error(e); Modal.createDialog(ErrorDialog, { title: _t("room_settings|permissions|error_changing_pl_title"), description: _t("room_settings|permissions|error_changing_pl_description"), }); - }); + + // Rethrow so that the PowerSelector can roll back + throw e; + } }; public render(): React.ReactNode { diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx index 0b345322180..7ec29d43662 100644 --- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx @@ -256,7 +256,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> - {_t("labs_mjolnir|advanced_warning")} + {_t("labs_mjolnir|advanced_warning")}

{_t("labs_mjolnir|explainer_1", { brand }, { code: (s) => {s} })}

{_t("labs_mjolnir|explainer_2")}

@@ -289,7 +289,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> heading={_t("labs_mjolnir|lists_heading")} description={ <> - {_t("labs_mjolnir|lists_description_1")} + {_t("labs_mjolnir|lists_description_1")}   {_t("labs_mjolnir|lists_description_2")} diff --git a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx index f6374ef32a9..098f2d828cf 100644 --- a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx +++ b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentre.tsx @@ -32,6 +32,8 @@ import { useUnreadThreadRooms } from "./useUnreadThreadRooms"; import { StatelessNotificationBadge } from "../../rooms/NotificationBadge/StatelessNotificationBadge"; import { NotificationLevel } from "../../../../stores/notifications/NotificationLevel"; import PosthogTrackers from "../../../../PosthogTrackers"; +import { getKeyBindingsManager } from "../../../../KeyBindingsManager"; +import { KeyBindingAction } from "../../../../accessibility/KeyboardShortcuts"; interface ThreadsActivityCentreProps { /** @@ -49,41 +51,56 @@ export function ThreadsActivityCentre({ displayButtonLabel }: ThreadsActivityCen const roomsAndNotifications = useUnreadThreadRooms(open); return ( - { - // Track only when the Threads Activity Centre is opened - if (newOpen) PosthogTrackers.trackInteraction("WebThreadsActivityCentreButton"); +
{ + // Do nothing if the TAC is closed + if (!open) return; - setOpen(newOpen); + const action = getKeyBindingsManager().getNavigationAction(evt); + + // Block spotlight opening + if (action === KeyBindingAction.FilterRooms) { + evt.stopPropagation(); + } }} - side="right" - title={_t("threads_activity_centre|header")} - trigger={ - - } > - {/* Make the content of the pop-up scrollable */} -
- {roomsAndNotifications.rooms.map(({ room, notificationLevel }) => ( - setOpen(false)} + { + // Track only when the Threads Activity Centre is opened + if (newOpen) PosthogTrackers.trackInteraction("WebThreadsActivityCentreButton"); + + setOpen(newOpen); + }} + side="right" + title={_t("threads_activity_centre|header")} + trigger={ + - ))} - {roomsAndNotifications.rooms.length === 0 && ( -
- {_t("threads_activity_centre|no_rooms_with_unreads_threads")} -
- )} -
-
+ } + > + {/* Make the content of the pop-up scrollable */} +
+ {roomsAndNotifications.rooms.map(({ room, notificationLevel }) => ( + setOpen(false)} + /> + ))} + {roomsAndNotifications.rooms.length === 0 && ( +
+ {_t("threads_activity_centre|no_rooms_with_unreads_threads")} +
+ )} +
+ + ); } @@ -105,10 +122,10 @@ interface ThreadsActivityRow { /** * Display a room with unread threads. */ -function ThreadsActivityRow({ room, onClick, notificationLevel }: ThreadsActivityRow): JSX.Element { +function ThreadsActivityCentreRow({ room, onClick, notificationLevel }: ThreadsActivityRow): JSX.Element { return ( { onClick(); diff --git a/src/customisations/Media.ts b/src/customisations/Media.ts index 05f91325dd7..25e8489658d 100644 --- a/src/customisations/Media.ts +++ b/src/customisations/Media.ts @@ -15,10 +15,11 @@ */ import { MatrixClient, ResizeMethod } from "matrix-js-sdk/src/matrix"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import { Optional } from "matrix-events-sdk"; import { MatrixClientPeg } from "../MatrixClientPeg"; -import { IMediaEventContent, IPreparedMedia, prepEventContentAsMedia } from "./models/IMediaEventContent"; +import { IPreparedMedia, prepEventContentAsMedia } from "./models/IMediaEventContent"; import { UserFriendlyError } from "../languageHandler"; // Populate this class with the details of your customisations when copying it. @@ -154,11 +155,11 @@ export class Media { /** * Creates a media object from event content. - * @param {IMediaEventContent} content The event content. + * @param {MediaEventContent} content The event content. * @param {MatrixClient} client? Optional client to use. * @returns {Media} The media object. */ -export function mediaFromContent(content: Partial, client?: MatrixClient): Media { +export function mediaFromContent(content: Partial, client?: MatrixClient): Media { return new Media(prepEventContentAsMedia(content), client); } diff --git a/src/customisations/models/IMediaEventContent.ts b/src/customisations/models/IMediaEventContent.ts index 81714000d9b..ad305239b15 100644 --- a/src/customisations/models/IMediaEventContent.ts +++ b/src/customisations/models/IMediaEventContent.ts @@ -14,220 +14,7 @@ * limitations under the License. */ -// TODO: These types should be elsewhere. - -import { MsgType } from "matrix-js-sdk/src/matrix"; - -import { BLURHASH_FIELD } from "../../utils/image-media"; - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#extensions-to-mroommessage-msgtypes - */ -export interface EncryptedFile { - /** - * The URL to the file. - */ - url: string; - /** - * A JSON Web Key object. - */ - key: { - alg: string; - key_ops: string[]; // eslint-disable-line camelcase - kty: string; - k: string; - ext: boolean; - }; - /** - * The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64. - */ - iv: string; - /** - * A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64. - * Clients should support the SHA-256 hash, which uses the key sha256. - */ - hashes: { [alg: string]: string }; - /** - * Version of the encrypted attachment's protocol. Must be v2. - */ - v: string; -} - -interface ThumbnailInfo { - /** - * The mimetype of the image, e.g. image/jpeg. - */ - mimetype?: string; - /** - * The intended display width of the image in pixels. - * This may differ from the intrinsic dimensions of the image file. - */ - w?: number; - /** - * The intended display height of the image in pixels. - * This may differ from the intrinsic dimensions of the image file. - */ - h?: number; - /** - * Size of the image in bytes. - */ - size?: number; -} - -interface BaseInfo { - mimetype?: string; - size?: number; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mfile - */ -export interface FileInfo extends BaseInfo { - /** - * @see https://github.com/matrix-org/matrix-spec-proposals/pull/2448 - */ - [BLURHASH_FIELD]?: string; - /** - * Information on the encrypted thumbnail file, as specified in End-to-end encryption. - * Only present if the thumbnail is encrypted. - * @see https://spec.matrix.org/v1.7/client-server-api/#sending-encrypted-attachments - */ - thumbnail_file?: EncryptedFile; - /** - * Metadata about the image referred to in thumbnail_url. - */ - thumbnail_info?: ThumbnailInfo; - /** - * The URL to the thumbnail of the file. Only present if the thumbnail is unencrypted. - */ - thumbnail_url?: string; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mimage - * - */ -export interface ImageInfo extends FileInfo, ThumbnailInfo {} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mimage - */ -export interface AudioInfo extends BaseInfo { - /** - * The duration of the audio in milliseconds. - */ - duration?: number; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mvideo - */ -export interface VideoInfo extends AudioInfo, ImageInfo { - /** - * The duration of the video in milliseconds. - */ - duration?: number; -} - -export type IMediaEventInfo = FileInfo | ImageInfo | AudioInfo | VideoInfo; - -interface BaseContent { - /** - * Required if the file is encrypted. Information on the encrypted file, as specified in End-to-end encryption. - * @see https://spec.matrix.org/v1.7/client-server-api/#sending-encrypted-attachments - */ - file?: EncryptedFile; - /** - * Required if the file is unencrypted. The URL (typically mxc:// URI) to the file. - */ - url?: string; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mfile - */ -export interface FileContent extends BaseContent { - /** - * A human-readable description of the file. - * This is recommended to be the filename of the original upload. - */ - body: string; - /** - * The original filename of the uploaded file. - */ - filename?: string; - /** - * Information about the file referred to in url. - */ - info?: FileInfo; - /** - * One of: [m.file]. - */ - msgtype: MsgType.File; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mimage - */ -export interface ImageContent extends BaseContent { - /** - * A textual representation of the image. - * This could be the alt text of the image, the filename of the image, - * or some kind of content description for accessibility e.g. ‘image attachment’. - */ - body: string; - /** - * Metadata about the image referred to in url. - */ - info?: ImageInfo; - /** - * One of: [m.image]. - */ - msgtype: MsgType.Image; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#maudio - */ -export interface AudioContent extends BaseContent { - /** - * A description of the audio e.g. ‘Bee Gees - Stayin’ Alive’, - * or some kind of content description for accessibility e.g. ‘audio attachment’. - */ - body: string; - /** - * Metadata for the audio clip referred to in url. - */ - info?: AudioInfo; - /** - * One of: [m.audio]. - */ - msgtype: MsgType.Audio; -} - -/** - * @see https://spec.matrix.org/v1.7/client-server-api/#mvideo - */ -export interface VideoContent extends BaseContent { - /** - * A description of the video e.g. ‘Gangnam style’, - * or some kind of content description for accessibility e.g. ‘video attachment’. - */ - body: string; - /** - * Metadata about the video clip referred to in url. - */ - info?: VideoInfo; - /** - * One of: [m.video]. - */ - msgtype: MsgType.Video; -} - -/** - * Type representing media event contents for `m.room.message` events listed in the Matrix specification - */ -export type IMediaEventContent = FileContent | ImageContent | AudioContent | VideoContent; +import { EncryptedFile, MediaEventContent } from "matrix-js-sdk/src/types"; export interface IPreparedMedia extends IMediaObject { thumbnail?: IMediaObject; @@ -241,11 +28,11 @@ export interface IMediaObject { /** * Parses an event content body into a prepared media object. This prepared media object * can be used with other functions to manipulate the media. - * @param {IMediaEventContent} content Unredacted media event content. See interface. + * @param {MediaEventContent} content Unredacted media event content. See interface. * @returns {IPreparedMedia} A prepared media object. * @throws Throws if the given content cannot be packaged into a prepared media object. */ -export function prepEventContentAsMedia(content: Partial): IPreparedMedia { +export function prepEventContentAsMedia(content: Partial): IPreparedMedia { let thumbnail: IMediaObject | undefined; if (typeof content?.info === "object" && "thumbnail_url" in content.info && content.info.thumbnail_url) { thumbnail = { diff --git a/src/hooks/room/useRoomCall.ts b/src/hooks/room/useRoomCall.ts index 8d9045825c1..92f350087fb 100644 --- a/src/hooks/room/useRoomCall.ts +++ b/src/hooks/room/useRoomCall.ts @@ -14,9 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Room } from "matrix-js-sdk/src/matrix"; +import { JoinRule, Room } from "matrix-js-sdk/src/matrix"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { CallType } from "matrix-js-sdk/src/webrtc/call"; +import { logger } from "matrix-js-sdk/src/logger"; import { useFeatureEnabled } from "../useSettings"; import SdkConfig from "../../SdkConfig"; @@ -39,6 +40,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { Action } from "../../dispatcher/actions"; import { CallStore, CallStoreEvent } from "../../stores/CallStore"; +import { calculateRoomVia } from "../../utils/permalinks/Permalinks"; export enum PlatformCallType { ElementCall, @@ -78,27 +80,35 @@ export const useRoomCall = ( videoCallClick(evt: React.MouseEvent | undefined, selectedType: PlatformCallType): void; toggleCallMaximized: () => void; isViewingCall: boolean; + generateCallLink: () => URL; + canGenerateCallLink: boolean; isConnectedToCall: boolean; hasActiveCallSession: boolean; callOptions: PlatformCallType[]; } => { + // settings const groupCallsEnabled = useFeatureEnabled("feature_group_calls"); const useElementCallExclusively = useMemo(() => { return SdkConfig.get("element_call").use_exclusively; }, []); + const guestSpaUrl = useMemo(() => { + return SdkConfig.get("element_call").guest_spa_url; + }, []); + const hasLegacyCall = useEventEmitterState( LegacyCallHandler.instance, LegacyCallHandlerEvent.CallsChanged, () => LegacyCallHandler.instance.getCallForRoom(room.roomId) !== null, ); - + // settings const widgets = useWidgets(room); const jitsiWidget = useMemo(() => widgets.find((widget) => WidgetType.JITSI.matches(widget.type)), [widgets]); const hasJitsiWidget = !!jitsiWidget; const managedHybridWidget = useMemo(() => widgets.find(isManagedHybridWidget), [widgets]); const hasManagedHybridWidget = !!managedHybridWidget; + // group call const groupCall = useCall(room.roomId); const isConnectedToCall = useConnectionState(groupCall) === ConnectionState.Connected; const hasGroupCall = groupCall !== null; @@ -107,11 +117,14 @@ export const useRoomCall = ( SdkContextClass.instance.roomViewStore.isViewingCall(), ); + // room const memberCount = useRoomMemberCount(room); - const [mayEditWidgets, mayCreateElementCalls] = useRoomState(room, () => [ + const [mayEditWidgets, mayCreateElementCalls, canJoinWithoutInvite] = useRoomState(room, () => [ room.currentState.mayClientSendStateEvent("im.vector.modular.widgets", room.client), room.currentState.mayClientSendStateEvent(ElementCall.MEMBER_EVENT_TYPE.name, room.client), + room.getJoinRule() === "public" || room.getJoinRule() === JoinRule.Knock, + /*|| room.getJoinRule() === JoinRule.Restricted <- rule for joining via token?*/ ]); // The options provided to the RoomHeader. @@ -131,7 +144,7 @@ export const useRoomCall = ( return [PlatformCallType.ElementCall]; } if (hasGroupCall && WidgetType.CALL.matches(groupCall.widget.type)) { - // only allow joining joining the ongoing Element call if there is one. + // only allow joining the ongoing Element call if there is one. return [PlatformCallType.ElementCall]; } } @@ -258,6 +271,26 @@ export const useRoomCall = ( }); }, [isViewingCall, room.roomId]); + const generateCallLink = useCallback(() => { + if (!canJoinWithoutInvite) + throw new Error("Cannot create link for room that users can not join without invite."); + if (!guestSpaUrl) throw new Error("No guest SPA url for external links provided."); + const url = new URL(guestSpaUrl); + url.pathname = "/room/"; + // Set params for the sharable url + url.searchParams.set("roomId", room.roomId); + url.searchParams.set("perParticipantE2EE", "true"); + for (const server of calculateRoomVia(room)) { + url.searchParams.set("viaServers", server); + } + + // Move params into hash + url.hash = "/" + room.name + url.search; + url.search = ""; + + logger.info("Generated element call external url:", url); + return url; + }, [canJoinWithoutInvite, guestSpaUrl, room]); /** * We've gone through all the steps */ @@ -268,6 +301,8 @@ export const useRoomCall = ( videoCallClick, toggleCallMaximized: toggleCallMaximized, isViewingCall: isViewingCall, + generateCallLink, + canGenerateCallLink: guestSpaUrl !== undefined && canJoinWithoutInvite, isConnectedToCall: isConnectedToCall, hasActiveCallSession: hasActiveCallSession, callOptions, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c974dc5f8b1..348b7a9ed5d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2896,6 +2896,9 @@ "link_title": "Link to room", "permalink_message": "Link to selected message", "permalink_most_recent": "Link to most recent message", + "share_call": "Conference invite link", + "share_call_subtitle": "Link for external users to join the call without a matrix account:", + "title_link": "Share Link", "title_message": "Share Room Message", "title_room": "Share Room", "title_user": "Share User" @@ -3828,6 +3831,7 @@ "expand": "Return to call", "failed_call_live_broadcast_description": "You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call.", "failed_call_live_broadcast_title": "Can’t start a call", + "get_call_link": "Share call link", "hangup": "Hangup", "hide_sidebar_button": "Hide sidebar", "input_devices": "Input devices", diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index bb2560e3c4d..0d518db05ea 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -1056,6 +1056,7 @@ "group_profile": "Profilo", "group_rooms": "Ĉambroj", "group_spaces": "Aroj", + "group_threads": "Fadenoj", "group_voip": "Voĉo kaj vido", "group_widgets": "Fenestraĵoj", "html_topic": "Montru HTML-prezenton de ĉambrotemoj", diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json index 0aec099268c..1e7cdab6e4e 100644 --- a/src/i18n/strings/et.json +++ b/src/i18n/strings/et.json @@ -1,6 +1,8 @@ { "a11y": { + "emoji_picker": "Emojide valija", "jump_first_invite": "Siirdu esimese kutse juurde.", + "message_composer": "Sõnumikoostaja", "n_unread_messages": { "other": "%(count)s lugemata teadet.", "one": "1 lugemata teade." @@ -9,7 +11,10 @@ "one": "1 lugemata mainimine.", "other": "%(count)s lugemata sõnumit kaasa arvatud mainimised." }, + "recent_rooms": "Hiljuti kasutatud jututoad", "room_name": "Jututuba %(name)s", + "room_status_bar": "Jututoa olekuriba", + "seek_bar_label": "Heli kerimisriba", "unread_messages": "Lugemata sõnumid.", "user_menu": "Kasutajamenüü" }, @@ -30,7 +35,7 @@ "click": "Klõpsi", "click_to_copy": "Kopeerimiseks klõpsa", "close": "Sulge", - "collapse": "ahenda", + "collapse": "Ahenda", "complete": "Valmis", "confirm": "Kinnita", "continue": "Jätka", @@ -50,7 +55,7 @@ "enable": "Võta kasutusele", "enter_fullscreen": "Lülita täisekraanivaade sisse", "exit_fullscreeen": "Lülita täisekraanivaade välja", - "expand": "laienda", + "expand": "Laienda", "explore_public_rooms": "Sirvi avalikke jututubasid", "explore_rooms": "Tutvu jututubadega", "export": "Ekspordi", @@ -319,7 +324,7 @@ "set_email_prompt": "Kas sa soovid seadistada e-posti aadressi?", "sign_in_description": "Jätkamaks kasuta oma kontot.", "sign_in_instead": "Pigem logi sisse", - "sign_in_instead_prompt": "Pigem logi sisse", + "sign_in_instead_prompt": "Sul juba on kasutajakonto olemas?
Siis logi siin sisse", "sign_in_or_register": "Logi sisse või loo uus konto", "sign_in_or_register_description": "Jätkamaks kasuta oma kontot või loo uus konto.", "sign_in_prompt": "Sul on kasutajakonto olemas? Siis logi sisse", @@ -1052,9 +1057,13 @@ "unknown_error_code": "tundmatu veakood", "update_power_level": "Õiguste muutmine ei õnnestunud" }, - "error_app_open_in_another_tab": "%(brand)s on avatud teises vahekaardis.", + "error_app_open_in_another_tab": "%(brand)s'i kasutamiseks ava teine vahekaart. Selle vahekaardi võid kinni panna.", + "error_app_open_in_another_tab_title": "%(brand)s'i on kasutatav teisel vahekaardil", "error_app_opened_in_another_window": "%(brand)s on avatud teises aknas. Klõpsa \"%(label)s\", et kasutada siin %(brand)s ja katkestada teise akna ühendus.", - "error_database_closed_title": "Andmebaasiühendus sulgus ootamatult", + "error_database_closed_description": { + "for_desktop": "Andmekandja maht võib olla täis saanud. Palun tee ruumi juurde ja laadi leht uuesti." + }, + "error_database_closed_title": "%(brand)s lõpetas ootamatult töö", "error_dialog": { "copy_room_link_failed": { "description": "Jututoa lingi kopeerimine lõikelauale ei õnnestunud.", @@ -1299,6 +1308,7 @@ }, "keyboard": { "activate_button": "Aktiveeri valitud nupp", + "alt": "Alt", "autocomplete_cancel": "Lülita automaatne sõnalõpetus välja", "autocomplete_force": "Sunni lõpetama", "autocomplete_navigate_next": "Järgmine sisestussoovitus", @@ -1322,9 +1332,13 @@ "composer_toggle_link": "Lülita link sisse/välja", "composer_toggle_quote": "Lülita tsiteerimine sisse/välja", "composer_undo": "Võta muudatus tagasi", + "control": "Ctrl", "dismiss_read_marker_and_jump_bottom": "Ära arvesta loetud sõnumite järjehoidjat ning mine kõige lõppu", + "end": "End", + "enter": "Enter", + "escape": "Esc", "go_home_view": "Avalehele", - "home": "Avaleht", + "home": "Home", "jump_first_message": "Mine esimese sõnumi juurde", "jump_last_message": "Mine viimase sõnumi juurde", "jump_room_search": "Suundu jututoa otsingusse", @@ -1336,7 +1350,10 @@ "navigate_prev_message_edit": "Muutmiseks liigu eelmise sõnumi juurde", "next_room": "Järgmine otsevestlus või jututuba", "next_unread_room": "Järgmine lugemata otsevestlus või jututuba", + "number": "[number]", "open_user_settings": "Ava kasutaja seadistused", + "page_down": "Page Down", + "page_up": "Page Up", "prev_room": "Eelmine otsevestlus või jututuba", "prev_unread_room": "Eelmine lugemata otsevestlus või jututuba", "room_list_collapse_section": "Ahenda jututubade loendi valikut", @@ -1348,6 +1365,7 @@ "scroll_up_timeline": "Liigu ajajoonel üles", "search": "Otsing (peab olema lubatud)", "send_sticker": "Saada kleeps", + "shift": "Shift", "space": "Tühikuklahv", "switch_to_space": "Vaata kogukonnakeskust tema numbri alusel", "toggle_hidden_events": "Lülita peidetud sündmuste näitamine sisse/välja", @@ -1383,6 +1401,7 @@ "element_call_video_rooms": "Element Call videotoad", "experimental_description": "Soovid katsetada? Proovi meie uusimaid arendusmõtteid. Need funktsionaalsused pole üldsegi veel valmis, nad võivad toimida puudulikult, võivad muutuda või sootuks lõpetamata jääda. Lisateavet leiad siit.", "experimental_section": "Varased arendusjärgud", + "feature_disable_call_per_sender_encryption": "Lülita Element Call'i kasutamisel krüptimine kasutajakohaselt välja", "feature_wysiwyg_composer_description": "Sõnumite kirjutamisel kasuta Markdown'i asemel täisfunktsionaalset küljendust.", "group_calls": "Uus rühmakõnede lahendus", "group_developer": "Arendajad", @@ -1413,11 +1432,17 @@ "new_room_decoration_ui": "Uus jututoa päis ja infovaade on hetkel aktiivses arenduses", "notification_settings": "Uued teavituste seadistused", "notification_settings_beta_title": "Teavituste seadistused", - "oidc_native_flow": "Luba OIDC liidestus (aktiivselt arendamisel)", + "notifications": "Kasuta jututoa päises teavituste riba", + "oidc_native_flow": "OIDC-põhine autentimine", + "oidc_native_flow_description": "⚠ HOIATUS: Kasuta OIDC liidestust, kui server seda võimaldab (aktiivselt arendamisel).", "pinning": "Sõnumite esiletõstmine", "report_to_moderators": "Teata moderaatoritele", "report_to_moderators_description": "Kui jututoas on modereerimine kasutusel, siis nupust „Teata sisust“ avaneva vormi abil saad jututoa reegleid rikkuvast sisust teatada moderaatoritele.", "rust_crypto": "Rust'is teostatud krüptolahendus", + "rust_crypto_in_config": "Rust'i krüptograafiat ei saa selles %(brand)s'i paigalduses välja lülitada", + "rust_crypto_in_config_description": "Rust'i teekidel põhineva krüptograafia kasutusele võtmine eeldab andmete ümbertõstmist ja selleks võib kuluda õige mitu minutit. Hiljem ei saa seda funktsionaalsust enam välja lülitada. Palun ole kindel, et tead, mida teed!", + "rust_crypto_optin_warning": "Rust'i teekidel põhineva krüptograafia kasutusele võtmine eeldab andmete ümbertõstmist ja selleks võib kuluda õige mitu minutit. Selle funktsionaalsuse väljalülitamiseks pead võrgust välja logima ning seejärel tagasi logima. Palun ole kindel, et tead, mida teed!", + "rust_crypto_requires_logout": "Kui Rust'i põhised teegid on kasutusel, siis selle funktsionaalsuse väljalülitamiseks pead võrgust välja logima ning seejärel tagasi logima", "sliding_sync": "Järkjärgulise sünkroniseerimise režiim", "sliding_sync_checking": "Kontrollin…", "sliding_sync_configuration": "Sliding Sync konfiguratsioon", @@ -1560,6 +1585,7 @@ "toast_description": "%(brand)s toimib nutiseadme veebibrauseris kastseliselt. Parima kasutajakogemuse ja uusima funktsionaalsuse jaoks kasuta meie rakendust.", "toast_title": "Rakendusega saad Matrix'is suhelda parimal viisil" }, + "name_and_id": "%(name)s (%(userId)s)", "no_more_results": "Rohkem otsingutulemusi pole", "notif_panel": { "empty_description": "Sul pole nähtavaid teavitusi.", @@ -2267,6 +2293,8 @@ }, "join_rule_upgrade_upgrading_room": "Uuendan jututoa versiooni", "public_without_alias_warning": "Sellele jututoale viitamiseks palun lisa talle aadress.", + "publish_room": "Tee see jututuba nähtavaks avalikus jututubade kataloogis.", + "publish_space": "Tee see kogukond nähtavaks avalikus jututubade kataloogis.", "strict_encryption": "Ära iialgi saada sellest sessioonist krüptitud sõnumeid verifitseerimata sessioonidesse selles jututoas", "title": "Turvalisus ja privaatsus" }, @@ -2366,7 +2394,7 @@ "layout_irc": "IRC (katseline)", "match_system_theme": "Kasuta süsteemset teemat", "subheading": "Välimuse kohendused kehtivad vaid selles %(brand)s'i sessioonis.", - "timeline_image_size": "Ajajoone piltide suurus", + "timeline_image_size": "Piltide suurus ajajoonel", "use_high_contrast": "Kasuta kontrastset välimust" }, "automatic_language_detection_syntax_highlight": "Kasuta süntaksi esiletõstmisel automaatset keeletuvastust", @@ -2699,6 +2727,7 @@ "device_verified_description": "See sessioon on valmis turvaliseks sõnumivahetuseks.", "device_verified_description_current": "Sinu praegune sessioon on valmis turvaliseks sõnumivahetuseks.", "error_pusher_state": "Tõuketeavituste teenuse oleku määramine ei õnnestunud", + "error_set_name": "Sessiooni nime määramine ei õnnestunud", "filter_all": "Kõik", "filter_inactive": "Pole pidevas kasutuses", "filter_inactive_description": "Pole olnud kasutusel %(inactiveAgeDays)s või enam päeva", @@ -3080,6 +3109,9 @@ "show_thread_filter": "Näita:", "unable_to_decrypt": "Sõnumi dekrüptimine ei õnnestunud" }, + "threads_activity_centre": { + "no_rooms_with_unreads_threads": "Sul veel pole lugemata jutulõngadega jututubasid." + }, "time": { "about_day_ago": "umbes päev tagasi", "about_hour_ago": "umbes tund aega tagasi", @@ -3924,6 +3956,7 @@ "l33t": "Ennustatavatest asendustest nagu '@' 'a' asemel pole eriti kasu", "longerKeyboardPattern": "Kasuta pikemaid klahvikombinatsioone, kus vajutatud klahvid pole kõrvuti ega kohakuti", "noNeed": "Sa ei pea sisestama erilisi tähemärke, numbreid ega suurtähti", + "pwned": "Kui sa kasutad seda salasõna mujalgi, siis palun muuda ta siin ära.", "recentYears": "Väldi hiljutisi aastaid", "repeated": "Väldi korduvaid sõnu ja tähemärke", "reverseWords": "Tagurpidi kirjutatud sõnu pole eriti keeruline ära arvata", @@ -3937,6 +3970,7 @@ "extendedRepeat": "Kordusi, nagu „abcabcabc“ on vaid natuke raskem ära arvata kui „abc“", "keyPattern": "Lühikesi klahvijärjestusi on lihtne ära arvata", "namesByThemselves": "Nimesid ja perenimesid on lihtne ära arvata", + "pwned": "Sinu salasõna on muutunud laiemas internetis toimunud ründe tõttu avalikuks.", "recentYears": "Hiljutisi aastaid on lihtne ära arvata", "sequences": "Jadasid nagu „abc“ või „6543“ on lihtne ära arvata", "similarToCommon": "See on sarnane tavaliselt kasutatavatele salasõnadele", @@ -3944,6 +3978,7 @@ "straightRow": "Klaviatuuril järjest paiknevaid klahvikombinatsioone on lihtne ära arvata", "topHundred": "See on saja levinuima salasõna seas", "topTen": "See on kümne levinuima salasõna seas", + "userInputs": "Siin ei tohiks olla ei isiklikku ega selle lehega seotud andmeid.", "wordByItself": "Üksikut sõna on lihtne ära arvata" } } diff --git a/src/models/Call.ts b/src/models/Call.ts index b6c1cda662e..369f712534f 100644 --- a/src/models/Call.ts +++ b/src/models/Call.ts @@ -758,7 +758,7 @@ export class ElementCall extends Call { name: "Element Call", type: WidgetType.CALL.preferred, url: url.toString(), - // waitForIframeLoad: false, + waitForIframeLoad: false, data: ElementCall.getWidgetData( client, roomId, diff --git a/src/models/RoomUpload.ts b/src/models/RoomUpload.ts index d6e0be4ca97..cc1b35315f5 100644 --- a/src/models/RoomUpload.ts +++ b/src/models/RoomUpload.ts @@ -15,8 +15,7 @@ limitations under the License. */ import { IEventRelation, UploadProgress } from "matrix-js-sdk/src/matrix"; - -import { EncryptedFile } from "../customisations/models/IMediaEventContent"; +import { EncryptedFile } from "matrix-js-sdk/src/types"; export class RoomUpload { public readonly abortController = new AbortController(); diff --git a/src/utils/DecryptFile.ts b/src/utils/DecryptFile.ts index 9b72c13bd39..c72f57589f7 100644 --- a/src/utils/DecryptFile.ts +++ b/src/utils/DecryptFile.ts @@ -17,9 +17,9 @@ limitations under the License. // Pull in the encryption lib so that we can decrypt attachments. import encrypt from "matrix-encrypt-attachment"; import { parseErrorResponse } from "matrix-js-sdk/src/matrix"; +import { EncryptedFile, MediaEventInfo } from "matrix-js-sdk/src/types"; import { mediaFromContent } from "../customisations/Media"; -import { EncryptedFile, IMediaEventInfo } from "../customisations/models/IMediaEventContent"; import { getBlobSafeMimeType } from "./blobs"; export class DownloadError extends Error { @@ -44,10 +44,10 @@ export class DecryptError extends Error { * This passed to [link]{@link https://github.com/matrix-org/matrix-encrypt-attachment} * as the encryption info object, so will also have the those keys in addition to * the keys below. - * @param {IMediaEventInfo} info The info parameter taken from the matrix event. + * @param {MediaEventInfo} info The info parameter taken from the matrix event. * @returns {Promise} Resolves to a Blob of the file. */ -export async function decryptFile(file?: EncryptedFile, info?: IMediaEventInfo): Promise { +export async function decryptFile(file?: EncryptedFile, info?: MediaEventInfo): Promise { // throws if file is falsy const media = mediaFromContent({ file }); diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts index 8423a54ce4e..75511756f58 100644 --- a/src/utils/FileUtils.ts +++ b/src/utils/FileUtils.ts @@ -25,22 +25,22 @@ import { FileSizeReturnArray, FileSizeReturnObject, } from "filesize"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; -import { IMediaEventContent } from "../customisations/models/IMediaEventContent"; import { _t } from "../languageHandler"; /** * Extracts a human-readable label for the file attachment to use as * link text. * - * @param {IMediaEventContent} content The "content" key of the matrix event. + * @param {MediaEventContent} content The "content" key of the matrix event. * @param {string} fallbackText The fallback text * @param {boolean} withSize Whether to include size information. Default true. * @param {boolean} shortened Ensure the extension of the file name is visible. Default false. * @return {string} the human-readable link text for the attachment. */ export function presentableTextForFile( - content: IMediaEventContent, + content: MediaEventContent, fallbackText = _t("common|attachment"), withSize = true, shortened = false, diff --git a/src/utils/MediaEventHelper.ts b/src/utils/MediaEventHelper.ts index ea14b175ae9..b9ceae9db5d 100644 --- a/src/utils/MediaEventHelper.ts +++ b/src/utils/MediaEventHelper.ts @@ -15,12 +15,12 @@ limitations under the License. */ import { MatrixEvent, EventType, MsgType } from "matrix-js-sdk/src/matrix"; +import { FileContent, ImageContent, MediaEventContent } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; import { LazyValue } from "./LazyValue"; import { Media, mediaFromContent } from "../customisations/Media"; import { decryptFile } from "./DecryptFile"; -import { FileContent, ImageContent, IMediaEventContent } from "../customisations/models/IMediaEventContent"; import { IDestroyable } from "./IDestroyable"; // TODO: We should consider caching the blobs. https://github.com/vector-im/element-web/issues/17192 @@ -48,7 +48,7 @@ export class MediaEventHelper implements IDestroyable { public get fileName(): string { return ( this.event.getContent().filename || - this.event.getContent().body || + this.event.getContent().body || "download" ); } @@ -81,7 +81,7 @@ export class MediaEventHelper implements IDestroyable { private fetchSource = (): Promise => { if (this.media.isEncrypted) { - const content = this.event.getContent(); + const content = this.event.getContent(); return decryptFile(content.file!, content.info); } return this.media.downloadSource().then((r) => r.blob()); diff --git a/src/utils/exportUtils/Exporter.ts b/src/utils/exportUtils/Exporter.ts index 9a4f3d42089..57b19e618ba 100644 --- a/src/utils/exportUtils/Exporter.ts +++ b/src/utils/exportUtils/Exporter.ts @@ -15,6 +15,7 @@ limitations under the License. */ import { Direction, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; +import { MediaEventContent } from "matrix-js-sdk/src/types"; import { saveAs } from "file-saver"; import { logger } from "matrix-js-sdk/src/logger"; import sanitizeFilename from "sanitize-filename"; @@ -24,7 +25,6 @@ import { decryptFile } from "../DecryptFile"; import { mediaFromContent } from "../../customisations/Media"; import { formatFullDateNoDay, formatFullDateNoDayISO } from "../../DateUtils"; import { isVoiceMessage } from "../EventUtils"; -import { IMediaEventContent } from "../../customisations/models/IMediaEventContent"; import { _t } from "../../languageHandler"; import SdkConfig from "../../SdkConfig"; @@ -225,7 +225,7 @@ export default abstract class Exporter { let blob: Blob | undefined = undefined; try { const isEncrypted = event.isEncrypted(); - const content = event.getContent(); + const content = event.getContent(); const shouldDecrypt = isEncrypted && content.hasOwnProperty("file") && event.getType() !== "m.sticker"; if (shouldDecrypt) { blob = await decryptFile(content.file); diff --git a/src/utils/image-media.ts b/src/utils/image-media.ts index fa252ee1aee..096fddbcbe9 100644 --- a/src/utils/image-media.ts +++ b/src/utils/image-media.ts @@ -14,8 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { EncryptedFile } from "matrix-js-sdk/src/types"; + import { BlurhashEncoder } from "../BlurhashEncoder"; -import { EncryptedFile } from "../customisations/models/IMediaEventContent"; type ThumbnailableElement = HTMLImageElement | HTMLVideoElement; diff --git a/src/utils/pillify.tsx b/src/utils/pillify.tsx index f46892949e9..22fcaec99ae 100644 --- a/src/utils/pillify.tsx +++ b/src/utils/pillify.tsx @@ -17,11 +17,11 @@ limitations under the License. import React from "react"; import ReactDOM from "react-dom"; import { PushProcessor } from "matrix-js-sdk/src/pushprocessor"; -import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix"; +import { MatrixClient, MatrixEvent, RuleId } from "matrix-js-sdk/src/matrix"; import { TooltipProvider } from "@vector-im/compound-web"; import SettingsStore from "../settings/SettingsStore"; -import { Pill, PillType, pillRoomNotifLen, pillRoomNotifPos } from "../components/views/elements/Pill"; +import { Pill, pillRoomNotifLen, pillRoomNotifPos, PillType } from "../components/views/elements/Pill"; import { parsePermalink } from "./permalinks/Permalinks"; import { PermalinkParts } from "./permalinks/PermalinkConstructor"; @@ -127,7 +127,9 @@ export function pillifyLinks( if (roomNotifTextNodes.length > 0) { const pushProcessor = new PushProcessor(matrixClient); - const atRoomRule = pushProcessor.getPushRuleById(".m.rule.roomnotif"); + const atRoomRule = pushProcessor.getPushRuleById( + mxEvent.getContent()["m.mentions"] !== undefined ? RuleId.IsRoomMention : RuleId.AtRoomNotification, + ); if (atRoomRule && pushProcessor.ruleMatchesEvent(atRoomRule, mxEvent)) { // Now replace all those nodes with Pills for (const roomNotifTextNode of roomNotifTextNodes) { diff --git a/src/voice-broadcast/models/VoiceBroadcastRecording.ts b/src/voice-broadcast/models/VoiceBroadcastRecording.ts index 81e07646a9d..bafb910b8ae 100644 --- a/src/voice-broadcast/models/VoiceBroadcastRecording.ts +++ b/src/voice-broadcast/models/VoiceBroadcastRecording.ts @@ -26,6 +26,7 @@ import { RelationType, TypedEventEmitter, } from "matrix-js-sdk/src/matrix"; +import { EncryptedFile } from "matrix-js-sdk/src/types"; import { ChunkRecordedPayload, @@ -38,7 +39,6 @@ import { VoiceBroadcastRecorderEvent, } from ".."; import { uploadFile } from "../../ContentMessages"; -import { EncryptedFile } from "../../customisations/models/IMediaEventContent"; import { createVoiceMessageContent } from "../../utils/createVoiceMessageContent"; import { IDestroyable } from "../../utils/IDestroyable"; import dis from "../../dispatcher/dispatcher"; diff --git a/test/accessibility/RovingTabIndex-test.tsx b/test/accessibility/RovingTabIndex-test.tsx index 4a2e67fece6..c2d5fbf0a86 100644 --- a/test/accessibility/RovingTabIndex-test.tsx +++ b/test/accessibility/RovingTabIndex-test.tsx @@ -16,6 +16,7 @@ limitations under the License. import React, { HTMLAttributes } from "react"; import { render } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { IState, @@ -364,4 +365,61 @@ describe("RovingTabIndex", () => { }); }); }); + + describe("handles arrow keys", () => { + it("should handle up/down arrow keys work when handleUpDown=true", async () => { + const { container } = render( + + {({ onKeyDownHandler }) => ( +
+ {button1} + {button2} + {button3} +
+ )} +
, + ); + + container.querySelectorAll("button")[0].focus(); + checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]); + + await userEvent.keyboard("[ArrowDown]"); + checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]); + + await userEvent.keyboard("[ArrowDown]"); + checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]); + + await userEvent.keyboard("[ArrowUp]"); + checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]); + + await userEvent.keyboard("[ArrowUp]"); + checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]); + + // Does not loop without + await userEvent.keyboard("[ArrowUp]"); + checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]); + }); + + it("should call scrollIntoView if specified", async () => { + const { container } = render( + + {({ onKeyDownHandler }) => ( +
+ {button1} + {button2} + {button3} +
+ )} +
, + ); + + container.querySelectorAll("button")[0].focus(); + checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]); + + const button = container.querySelectorAll("button")[1]; + const mock = jest.spyOn(button, "scrollIntoView"); + await userEvent.keyboard("[ArrowDown]"); + expect(mock).toHaveBeenCalled(); + }); + }); }); diff --git a/test/components/structures/__snapshots__/MessagePanel-test.tsx.snap b/test/components/structures/__snapshots__/MessagePanel-test.tsx.snap index c7767dddb29..e57c5363af7 100644 --- a/test/components/structures/__snapshots__/MessagePanel-test.tsx.snap +++ b/test/components/structures/__snapshots__/MessagePanel-test.tsx.snap @@ -94,7 +94,7 @@ exports[`MessagePanel should handle lots of membership events quickly 1`] = ` class="mx_GenericEventListSummary_avatars" > renders 1`] = ` class="mx_SpaceHierarchy_roomTile_avatar" > renders 1`] = ` class="mx_SpaceHierarchy_roomTile_avatar" > renders 1`] = ` class="mx_SpaceHierarchy_roomTile_avatar" > renders 1`] = ` class="mx_SpaceHierarchy_roomTile_avatar" > when video broadcast when rendered should render class="mx_UserMenu_userAvatar" > renders marker when beacon has location 1`] = ` class="mx_Marker_border" > renders own beacon status when user is live sharin class="mx_DialogOwnBeaconStatus" > renders sidebar correctly with beacons 1`] = ` class="mx_BeaconListItem" > { const sourceRoom = "!111111111111111111:example.org"; const aliceId = "@alice:example.org"; @@ -128,6 +135,37 @@ describe("ForwardDialog", () => { expect(container.querySelectorAll(".mx_ForwardList_entry")).toHaveLength(3); }); + it("should be navigable using arrow keys", async () => { + const { container } = mountForwardDialog(); + + const searchBox = getByTestId(container, "searchbox-input"); + searchBox.focus(); + await waitFor(() => + expect(container.querySelectorAll(".mx_ForwardList_entry")[0]).toHaveClass("mx_ForwardList_entry_active"), + ); + + await userEvent.keyboard("[ArrowDown]"); + await waitFor(() => + expect(container.querySelectorAll(".mx_ForwardList_entry")[1]).toHaveClass("mx_ForwardList_entry_active"), + ); + + await userEvent.keyboard("[ArrowDown]"); + await waitFor(() => + expect(container.querySelectorAll(".mx_ForwardList_entry")[2]).toHaveClass("mx_ForwardList_entry_active"), + ); + + await userEvent.keyboard("[ArrowUp]"); + await waitFor(() => + expect(container.querySelectorAll(".mx_ForwardList_entry")[1]).toHaveClass("mx_ForwardList_entry_active"), + ); + + await userEvent.keyboard("[Enter]"); + expect(mockClient.sendEvent).toHaveBeenCalledWith("A", "m.room.message", { + body: "Hello world!", + msgtype: "m.text", + }); + }); + it("tracks message sending progress across multiple rooms", async () => { mockPlatformPeg(); const { container } = mountForwardDialog(); diff --git a/test/components/views/dialogs/ShareDialog-test.tsx b/test/components/views/dialogs/ShareDialog-test.tsx new file mode 100644 index 00000000000..a78f4cf62ff --- /dev/null +++ b/test/components/views/dialogs/ShareDialog-test.tsx @@ -0,0 +1,130 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +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 { EventTimeline, MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix"; +import { render, RenderOptions } from "@testing-library/react"; +import { TooltipProvider } from "@vector-im/compound-web"; + +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; +import SettingsStore from "../../../../src/settings/SettingsStore"; +import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; +import { _t } from "../../../../src/languageHandler"; +import ShareDialog from "../../../../src/components/views/dialogs/ShareDialog"; +import { UIFeature } from "../../../../src/settings/UIFeature"; +import { stubClient } from "../../../test-utils"; +jest.mock("../../../../src/utils/ShieldUtils"); + +function getWrapper(): RenderOptions { + return { + wrapper: ({ children }) => ( + + + {children} + + + ), + }; +} + +describe("ShareDialog", () => { + let room: Room; + + const ROOM_ID = "!1:example.org"; + + beforeEach(async () => { + stubClient(); + room = new Room(ROOM_ID, MatrixClientPeg.get()!, "@alice:example.org"); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it("renders room share dialog", () => { + const { container: withoutEvents } = render(, getWrapper()); + expect(withoutEvents).toHaveTextContent(_t("share|title_room")); + + jest.spyOn(room, "getLiveTimeline").mockReturnValue({ getEvents: () => [{} as MatrixEvent] } as EventTimeline); + const { container: withEvents } = render(, getWrapper()); + expect(withEvents).toHaveTextContent(_t("share|permalink_most_recent")); + }); + + it("renders user share dialog", () => { + mockRoomMembers(room, 1); + const { container } = render( + , + getWrapper(), + ); + expect(container).toHaveTextContent(_t("share|title_user")); + }); + + it("renders link share dialog", () => { + mockRoomMembers(room, 1); + const { container } = render( + , + getWrapper(), + ); + expect(container).toHaveTextContent(_t("share|title_link")); + }); + + it("renders the QR code if configured", () => { + const originalGetValue = SettingsStore.getValue; + jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => { + if (feature === UIFeature.ShareQRCode) return true; + return originalGetValue(feature); + }); + const { container } = render(, getWrapper()); + const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_qrcode_container").length > 0; + expect(qrCodesVisible).toBe(true); + }); + + it("renders the social button if configured", () => { + const originalGetValue = SettingsStore.getValue; + jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => { + if (feature === UIFeature.ShareSocial) return true; + return originalGetValue(feature); + }); + const { container } = render(, getWrapper()); + const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_social_container").length > 0; + expect(qrCodesVisible).toBe(true); + }); + it("renders custom title and subtitle", () => { + const { container } = render( + , + getWrapper(), + ); + expect(container).toHaveTextContent("test_title_123"); + expect(container).toHaveTextContent("custom_subtitle_1234"); + }); +}); +/** + * + * @param count the number of users to create + */ +function mockRoomMembers(room: Room, count: number) { + const members = Array(count) + .fill(0) + .map((_, index) => new RoomMember(room.roomId, "@alice:example.org")); + + room.currentState.setJoinedMemberCount(members.length); + room.getJoinedMembers = jest.fn().mockReturnValue(members); +} diff --git a/test/components/views/dialogs/__snapshots__/ConfirmUserActionDialog-test.tsx.snap b/test/components/views/dialogs/__snapshots__/ConfirmUserActionDialog-test.tsx.snap index 31b516d9862..280389922db 100644 --- a/test/components/views/dialogs/__snapshots__/ConfirmUserActionDialog-test.tsx.snap +++ b/test/components/views/dialogs/__snapshots__/ConfirmUserActionDialog-test.tsx.snap @@ -41,7 +41,7 @@ exports[`ConfirmUserActionDialog renders 1`] = ` class="mx_ConfirmUserActionDialog_avatar" > should list spaces which are not par
", () => { expect(option.selected).toBeTruthy(); expect(fn).not.toHaveBeenCalled(); }); + + it("should reset when onChange promise rejects", async () => { + const deferred = defer(); + render( + deferred.promise} + powerLevelKey="key" + />, + ); + + const input = screen.getByLabelText("Power level"); + fireEvent.change(input, { target: { value: 40 } }); + fireEvent.blur(input); + + await screen.findByDisplayValue(40); + deferred.reject("Some error"); + await screen.findByDisplayValue(25); + }); }); diff --git a/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap b/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap index 4771fc776e4..92b89013e10 100644 --- a/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap +++ b/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap @@ -47,7 +47,7 @@ exports[`AppTile destroys non-persisted right panel widget on room change 1`] = id="1" >
renders with a tooltip 1`] = ` tabindex="0" >
should render the expected pill for @room 1`] = ` >
", () => { const { container } = getComponent({ mxEvent: ev }); const content = container.querySelector(".mx_EventTile_body"); expect(content.innerHTML).toMatchInlineSnapshot( - `"Chat with Member"`, + `"Chat with Member"`, ); }); diff --git a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap index 66c397c9a9f..c91ed6c6d85 100644 --- a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap +++ b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap @@ -83,7 +83,7 @@ exports[`MLocationBody without error renders marker correctly fo class="mx_Marker_border" > renders formatted m.text correctly pills appear for an
Message #49
  • @user48:example.com
    Message #48
  • @user47:example.com
    Message #47
  • @user46:example.com
    Message #46
  • @user45:example.com
    Message #45
  • @user44:example.com
    Message #44
  • @user43:example.com
    Message #43
  • @user42:example.com
    Message #42
  • @user41:example.com
    Message #41
  • @user40:example.com
    Message #40
  • @user39:example.com
    Message #39
  • @user38:example.com
    Message #38
  • @user37:example.com
    Message #37
  • @user36:example.com
    Message #36
  • @user35:example.com
    Message #35
  • @user34:example.com
    Message #34
  • @user33:example.com
    Message #33
  • @user32:example.com
    Message #32
  • @user31:example.com
    Message #31
  • @user30:example.com
    Message #30
  • @user29:example.com
    Message #29
  • @user28:example.com
    Message #28
  • @user27:example.com
    Message #27
  • @user26:example.com
    Message #26
  • @user25:example.com
    Message #25
  • @user24:example.com
    Message #24
  • @user23:example.com
    Message #23
  • @user22:example.com
    Message #22
  • @user21:example.com
    Message #21
  • @user20:example.com
    Message #20
  • @user19:example.com
    Message #19
  • @user18:example.com
    Message #18
  • @user17:example.com
    Message #17
  • @user16:example.com
    Message #16
  • @user15:example.com
    Message #15
  • @user14:example.com
    Message #14
  • @user13:example.com
    Message #13
  • @user12:example.com
    Message #12
  • @user11:example.com
    Message #11
  • @user10:example.com
    Message #10
  • @user9:example.com
    Message #9
  • @user8:example.com
    Message #8
  • @user7:example.com
    Message #7
  • @user6:example.com
    Message #6
  • @user5:example.com
    Message #5
  • @user4:example.com
    Message #4
  • @user3:example.com
    Message #3
  • @user2:example.com
    Message #2
  • @user1:example.com
    Message #1
  • @user0:example.com
    Message #0
  • +
  • @user49:example.com
    Message #49
  • @user48:example.com
    Message #48
  • @user47:example.com
    Message #47
  • @user46:example.com
    Message #46
  • @user45:example.com
    Message #45
  • @user44:example.com
    Message #44
  • @user43:example.com
    Message #43
  • @user42:example.com
    Message #42
  • @user41:example.com
    Message #41
  • @user40:example.com
    Message #40
  • @user39:example.com
    Message #39
  • @user38:example.com
    Message #38
  • @user37:example.com
    Message #37
  • @user36:example.com
    Message #36
  • @user35:example.com
    Message #35
  • @user34:example.com
    Message #34
  • @user33:example.com
    Message #33
  • @user32:example.com
    Message #32
  • @user31:example.com
    Message #31
  • @user30:example.com
    Message #30
  • @user29:example.com
    Message #29
  • @user28:example.com
    Message #28
  • @user27:example.com
    Message #27
  • @user26:example.com
    Message #26
  • @user25:example.com
    Message #25
  • @user24:example.com
    Message #24
  • @user23:example.com
    Message #23
  • @user22:example.com
    Message #22
  • @user21:example.com
    Message #21
  • @user20:example.com
    Message #20
  • @user19:example.com
    Message #19
  • @user18:example.com
    Message #18
  • @user17:example.com
    Message #17
  • @user16:example.com
    Message #16
  • @user15:example.com
    Message #15
  • @user14:example.com
    Message #14
  • @user13:example.com
    Message #13
  • @user12:example.com
    Message #12
  • @user11:example.com
    Message #11
  • @user10:example.com
    Message #10
  • @user9:example.com
    Message #9
  • @user8:example.com
    Message #8
  • @user7:example.com
    Message #7
  • @user6:example.com
    Message #6
  • @user5:example.com
    Message #5
  • @user4:example.com
    Message #4
  • @user3:example.com
    Message #3
  • @user2:example.com
    Message #2
  • @user1:example.com
    Message #1
  • @user0:example.com
    Message #0
  • diff --git a/test/utils/pillify-test.tsx b/test/utils/pillify-test.tsx index c5a00a68289..4c393ba458c 100644 --- a/test/utils/pillify-test.tsx +++ b/test/utils/pillify-test.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from "react"; import { render } from "@testing-library/react"; import { MatrixEvent, ConditionKind, EventType, PushRuleActionName, Room, TweakName } from "matrix-js-sdk/src/matrix"; +import { mocked } from "jest-mock"; import { pillifyLinks } from "../../src/utils/pillify"; import { stubClient } from "../test-utils"; @@ -36,7 +37,9 @@ describe("pillify", () => { beforeEach(() => { stubClient(); const cli = MatrixClientPeg.safeGet(); - (cli.getRoom as jest.Mock).mockReturnValue(new Room(roomId, cli, cli.getUserId()!)); + const room = new Room(roomId, cli, cli.getUserId()!); + room.currentState.mayTriggerNotifOfType = jest.fn().mockReturnValue(true); + (cli.getRoom as jest.Mock).mockReturnValue(room); cli.pushRules!.global = { override: [ { @@ -58,6 +61,28 @@ describe("pillify", () => { }, ], }, + { + rule_id: ".m.rule.is_room_mention", + default: true, + enabled: true, + conditions: [ + { + kind: ConditionKind.EventPropertyIs, + key: "content.m\\.mentions.room", + value: true, + }, + { + kind: ConditionKind.SenderNotificationPermission, + key: "room", + }, + ], + actions: [ + PushRuleActionName.Notify, + { + set_tweak: TweakName.Highlight, + }, + ], + }, ], }; @@ -81,6 +106,29 @@ describe("pillify", () => { expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room"); }); + it("should pillify @room in an intentional mentions world", () => { + mocked(MatrixClientPeg.safeGet().supportsIntentionalMentions).mockReturnValue(true); + const { container } = render(
    @room
    ); + const containers: Element[] = []; + pillifyLinks( + MatrixClientPeg.safeGet(), + [container], + new MatrixEvent({ + room_id: roomId, + type: EventType.RoomMessage, + content: { + "body": "@room", + "m.mentions": { + room: true, + }, + }, + }), + containers, + ); + expect(containers).toHaveLength(1); + expect(container.querySelector(".mx_Pill.mx_AtRoomPill")?.textContent).toBe("!@room"); + }); + it("should not double up pillification on repeated calls", () => { const { container } = render(
    @room
    ); const containers: Element[] = []; diff --git a/test/voice-broadcast/models/VoiceBroadcastRecording-test.ts b/test/voice-broadcast/models/VoiceBroadcastRecording-test.ts index 896e1b303a7..1298b1ff49e 100644 --- a/test/voice-broadcast/models/VoiceBroadcastRecording-test.ts +++ b/test/voice-broadcast/models/VoiceBroadcastRecording-test.ts @@ -29,9 +29,9 @@ import { Relations, SyncState, } from "matrix-js-sdk/src/matrix"; +import { EncryptedFile } from "matrix-js-sdk/src/types"; import { uploadFile } from "../../../src/ContentMessages"; -import { EncryptedFile } from "../../../src/customisations/models/IMediaEventContent"; import { createVoiceMessageContent } from "../../../src/utils/createVoiceMessageContent"; import { createVoiceBroadcastRecorder, diff --git a/yarn.lock b/yarn.lock index 3e08f5bd9fb..84e87730dc7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1449,7 +1449,7 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== -"@floating-ui/core@^1.6.0": +"@floating-ui/core@^1.0.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== @@ -1457,12 +1457,12 @@ "@floating-ui/utils" "^0.2.1" "@floating-ui/dom@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.1.tgz#d552e8444f77f2d88534372369b3771dc3a2fa5d" - integrity sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ== + version "1.6.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef" + integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw== dependencies: - "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.1" + "@floating-ui/core" "^1.0.0" + "@floating-ui/utils" "^0.2.0" "@floating-ui/react-dom@^2.0.0": version "2.0.8" @@ -1471,7 +1471,7 @@ dependencies: "@floating-ui/dom" "^1.6.1" -"@floating-ui/utils@^0.2.1": +"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== @@ -1849,9 +1849,9 @@ "@babel/runtime" "^7.17.9" "@matrix-org/spec@^1.7.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.8.0.tgz#5d46f0ddcdff01934a63aa1f070f0ce960326acc" - integrity sha512-QKPIfrJDz5kKiaFluSfFLqAHu1fyMpYAc7sLWSyxj2flPAbajyy4zM7kfyF5yh5iGrunVLXi1iDSXYoM5/a4ZQ== + version "1.9.0" + resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.9.0.tgz#ac43accc9b081ad443b11acd2d8d1f2919bd0e2f" + integrity sha512-BgPTYFhvjc10XWIEsqKsQOu5cR2BxMqpOhJ/IA/iiUeVOh4M5BjBR+ILZFGr8WV7TgH+h8rFdCy2kbaumRHkVg== "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" @@ -3021,9 +3021,9 @@ svg2vectordrawable "^2.9.1" "@vector-im/compound-web@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-3.1.1.tgz#4f3267e8c860475eb69de37e375950dc77a649a8" - integrity sha512-s+YQsMi5DotbHy47zP9Mrz19a4Vb0HF76JoHAita7QJkSqx+w/p1NECH4WTUnklbe8W3T5kVwSuwEx9eV8c2ZA== + version "3.1.3" + resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-3.1.3.tgz#bd23b4b2067b5ff0035b7c5f11bf6c57f98eb6be" + integrity sha512-h1uEKxMrZXUlEA2b8sd57WbxDy9LV8E0MYbz1vdKbU0n3lJb8neUbCAJE7PdQUoOSCi91jw8H+xH8XRLxTYYYw== dependencies: "@radix-ui/react-context-menu" "^2.1.5" "@radix-ui/react-dropdown-menu" "^2.0.6" @@ -3227,15 +3227,7 @@ aria-query@^5.0.0, aria-query@^5.3.0: dependencies: dequal "^2.0.3" -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - -array-buffer-byte-length@^1.0.1: +array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== @@ -3264,6 +3256,17 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.findlast@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz#eeb9e45fc894055c82e5675c463e8077b827ad36" + integrity sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + array.prototype.findlastindex@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" @@ -3285,7 +3288,7 @@ array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: +array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -3295,29 +3298,26 @@ array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.tosorted@^1.1.1: +array.prototype.toreversed@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz#620eff7442503d66c799d95503f82b475745cefd" - integrity sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg== + resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" + integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== dependencies: call-bind "^1.0.2" define-properties "^1.2.0" es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" - get-intrinsic "^1.2.1" -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== +array.prototype.tosorted@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" + integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.1.0" + es-shim-unscopables "^1.0.2" arraybuffer.prototype.slice@^1.0.3: version "1.0.3" @@ -3364,12 +3364,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -available-typed-arrays@^1.0.6: +available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== @@ -3616,16 +3611,7 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" - integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== - dependencies: - function-bind "^1.1.2" - get-intrinsic "^1.2.1" - set-function-length "^1.1.1" - -call-bind@^1.0.6, call-bind@^1.0.7: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -4149,16 +4135,7 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-data-property@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" - integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== - dependencies: - get-intrinsic "^1.2.1" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - -define-data-property@^1.1.2: +define-data-property@^1.0.1, define-data-property@^1.1.2, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -4434,7 +4411,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.5, es-abstract@^1.22.3: +es-abstract@^1.17.5: version "1.22.4" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.4.tgz#26eb2e7538c3271141f5754d31aabfdb215f27bf" integrity sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg== @@ -4521,50 +4498,52 @@ es-abstract@^1.18.3: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" -es-abstract@^1.22.1: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.22.4: + version "1.22.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" + integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.1" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.0" + safe-regex-test "^1.0.3" string.prototype.trim "^1.2.8" string.prototype.trimend "^1.0.7" string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.5" unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" + which-typed-array "^1.1.14" es-define-property@^1.0.0: version "1.0.0" @@ -4573,7 +4552,7 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.0.0, es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== @@ -4593,7 +4572,7 @@ es-get-iterator@^1.1.3: isarray "^2.0.5" stop-iteration-iterator "^1.0.0" -es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: +es-iterator-helpers@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== @@ -4613,16 +4592,28 @@ es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: iterator.prototype "^1.1.2" safe-array-concat "^1.0.1" -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== +es-iterator-helpers@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz#123d1315780df15b34eb181022da43e734388bb8" + integrity sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ== dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" + asynciterator.prototype "^1.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.22.4" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.0" -es-set-tostringtag@^2.0.2: +es-set-tostringtag@^2.0.1, es-set-tostringtag@^2.0.2, es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== @@ -4631,7 +4622,7 @@ es-set-tostringtag@^2.0.2: has-tostringtag "^1.0.2" hasown "^2.0.1" -es-shim-unscopables@^1.0.0: +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== @@ -4777,26 +4768,28 @@ eslint-plugin-react-hooks@^4.3.0: integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react@^7.28.0: - version "7.33.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" - integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== + version "7.34.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz#ab71484d54fc409c37025c5eca00eb4177a5e88c" + integrity sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ== dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" + array-includes "^3.1.7" + array.prototype.findlast "^1.2.4" + array.prototype.flatmap "^1.3.2" + array.prototype.toreversed "^1.1.2" + array.prototype.tosorted "^1.1.3" doctrine "^2.1.0" - es-iterator-helpers "^1.0.12" + es-iterator-helpers "^1.0.17" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" + object.entries "^1.1.7" + object.fromentries "^2.0.7" + object.hasown "^1.1.3" + object.values "^1.1.7" prop-types "^15.8.1" - resolve "^2.0.0-next.4" + resolve "^2.0.0-next.5" semver "^6.3.1" - string.prototype.matchall "^4.0.8" + string.prototype.matchall "^4.0.10" eslint-plugin-unicorn@^51.0.0: version "51.0.1" @@ -5319,17 +5312,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.1, get-intrinsic@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" - integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== - dependencies: - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -5355,15 +5338,7 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-symbol-description@^1.0.2: +get-symbol-description@^1.0.0, get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== @@ -5515,7 +5490,7 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-d dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: +has-proto@^1.0.1, has-proto@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== @@ -5525,14 +5500,7 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -5576,9 +5544,9 @@ html-encoding-sniffer@^3.0.0: whatwg-encoding "^2.0.0" html-entities@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" - integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== html-escaper@^2.0.0: version "2.0.2" @@ -5711,7 +5679,7 @@ ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.4, internal-slot@^1.0.5: +internal-slot@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== @@ -5720,7 +5688,7 @@ internal-slot@^1.0.4, internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" -internal-slot@^1.0.7: +internal-slot@^1.0.5, internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== @@ -5754,16 +5722,7 @@ is-arguments@^1.1.1: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - -is-array-buffer@^3.0.4: +is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== @@ -5891,10 +5850,10 @@ is-map@^2.0.1, is-map@^2.0.2: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.2, is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -5943,12 +5902,12 @@ is-set@^2.0.1, is-set@^2.0.2: resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -5979,14 +5938,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== - dependencies: - which-typed-array "^1.1.11" - -is-typed-array@^1.1.13: +is-typed-array@^1.1.10, is-typed-array@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -6907,8 +6859,8 @@ matrix-events-sdk@0.0.1: integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "31.4.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/6176faef48e5f952a8be82354874fd87358e97a7" + version "31.5.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/461aeae2815a223c817c9768e26220cec4a69d12" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^4.6.0" @@ -7231,7 +7183,7 @@ object.assign@^4.1.4, object.assign@^4.1.5: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6, object.entries@^1.1.7: +object.entries@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== @@ -7240,7 +7192,7 @@ object.entries@^1.1.6, object.entries@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -object.fromentries@^2.0.6, object.fromentries@^2.0.7: +object.fromentries@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== @@ -7259,7 +7211,7 @@ object.groupby@^1.0.1: es-abstract "^1.22.1" get-intrinsic "^1.2.1" -object.hasown@^1.1.2: +object.hasown@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== @@ -7877,9 +7829,9 @@ react-redux@^7.2.0: react-is "^17.0.2" react-remove-scroll-bar@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" - integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + version "2.3.5" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.5.tgz#cd2543b3ed7716c7c5b446342d21b0e0b303f47c" + integrity sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw== dependencies: react-style-singleton "^2.2.1" tslib "^2.0.0" @@ -7995,14 +7947,15 @@ redux@^4.0.0, redux@^4.0.4: "@babel/runtime" "^7.9.2" reflect.getprototypeof@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" - integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== + version "1.0.5" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" + integrity sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.0.0" + get-intrinsic "^1.2.3" globalthis "^1.0.3" which-builtin-type "^1.1.3" @@ -8035,7 +7988,7 @@ regexp-tree@^0.1.27: resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== -regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: +regexp.prototype.flags@^1.4.3: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== @@ -8044,7 +7997,7 @@ regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0, regexp.prototype.f define-properties "^1.2.0" set-function-name "^2.0.0" -regexp.prototype.flags@^1.5.2: +regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== @@ -8156,7 +8109,7 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.4: +resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== @@ -8201,17 +8154,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-array-concat@^1.1.0: +safe-array-concat@^1.0.1, safe-array-concat@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== @@ -8231,16 +8174,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.1.tgz#207369b445fd007e534864635b28b2ae7b105783" - integrity sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g== - dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" - is-regex "^1.1.4" - -safe-regex-test@^1.0.3: +safe-regex-test@^1.0.0, safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== @@ -8360,7 +8294,7 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -set-function-length@^1.1.1, set-function-length@^1.2.1: +set-function-length@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== @@ -8373,13 +8307,14 @@ set-function-length@^1.1.1, set-function-length@^1.2.1: has-property-descriptors "^1.0.1" set-function-name@^2.0.0, set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" setimmediate@^1.0.5: version "1.0.5" @@ -8548,7 +8483,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8566,7 +8510,7 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.matchall@^4.0.8: +string.prototype.matchall@^4.0.10: version "4.0.10" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== @@ -8623,7 +8567,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8677,9 +8628,9 @@ stylelint-config-standard@^36.0.0: stylelint-config-recommended "^14.0.0" stylelint-scss@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.1.0.tgz#b7ef162c417132e8df2b69d1759ae07395d54fb5" - integrity sha512-kCfK8TQzthGwb4vaZniZgxRsVbCM4ZckmT1b/H5m4FU3I8Dz0id9llKsy1NMp3XXqC8+OPD4rVKtUbSxXlJb5g== + version "6.2.1" + resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.2.1.tgz#7675f3f5034a3b1d7d064d480e0d834ef9353244" + integrity sha512-ZoGLbVb1keZYRVGQlhB8G6sZOoNqw61whzzzGFWp05N12ErqLFfBv3JPrXiMLZaW98sBS7K/vUQhRnvUj4vwdw== dependencies: known-css-properties "^0.29.0" postcss-media-query-parser "^0.2.3" @@ -9015,16 +8966,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-buffer@^1.0.1: +typed-array-buffer@^1.0.1, typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== @@ -9033,35 +8975,40 @@ typed-array-buffer@^1.0.1: es-errors "^1.3.0" is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.0, typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.0, typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.4, typed-array-length@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" + integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typescript@5.3.3: version "5.3.3" @@ -9383,18 +9330,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== -which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which-typed-array@^1.1.14: +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== @@ -9419,8 +9355,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -9438,6 +9373,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"