Compare commits
28 Commits
dbkr/maste
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fdd313ae9 | ||
|
|
18cd641cf6 | ||
|
|
286231aa37 | ||
|
|
3f20df5e08 | ||
|
|
d5e070b300 | ||
|
|
d8ecb6362a | ||
|
|
bcc4ecf0cb | ||
|
|
24d9a174d7 | ||
|
|
7970b968c2 | ||
|
|
59e591c462 | ||
|
|
804cb62698 | ||
|
|
8bb4d44532 | ||
|
|
209ab59978 | ||
|
|
6ae11dab52 | ||
|
|
fac982811c | ||
|
|
d7730f417b | ||
|
|
829b588dbf | ||
|
|
9a7cc7eb34 | ||
|
|
e537da4251 | ||
|
|
094a7071e2 | ||
|
|
a5673f603f | ||
|
|
0c210b9b3a | ||
|
|
05df321f34 | ||
|
|
8116dc5f60 | ||
|
|
d090499329 | ||
|
|
6784d071a6 | ||
|
|
3f47487472 | ||
|
|
89e22e00fb |
4
.github/workflows/end-to-end-tests.yaml
vendored
@@ -37,8 +37,6 @@ env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
# Use 6 runners in the default case, but 4 when running on a schedule where we run all 5 projects (20 runners total)
|
||||
NUM_RUNNERS: ${{ github.event_name == 'schedule' && 4 || 6 }}
|
||||
# If run on the master branch, we need to fetch matching branches
|
||||
DEFAULT_BRANCH: ${{ github.ref == 'refs/heads/master' && 'master' || '' }}
|
||||
|
||||
permissions: {} # No permissions required
|
||||
|
||||
@@ -67,7 +65,7 @@ jobs:
|
||||
# tell layered.sh to check out the right sha of the JS-SDK & EW, if they were given one
|
||||
JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }}
|
||||
run: |
|
||||
scripts/layered.sh "$DEFAULT_BRANCH"
|
||||
scripts/layered.sh
|
||||
JSSDK_SHA=$(git -C matrix-js-sdk rev-parse --short=12 HEAD)
|
||||
VECTOR_SHA=$(git rev-parse --short=12 HEAD)
|
||||
echo "VERSION=$VECTOR_SHA--js-$JSSDK_SHA" >> $GITHUB_OUTPUT
|
||||
|
||||
6
.github/workflows/static_analysis.yaml
vendored
@@ -15,8 +15,6 @@ env:
|
||||
# These must be set for fetchdep.sh to get the right branch
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
# If run on the master branch, we need to fetch matching branches
|
||||
DEFAULT_BRANCH: ${{ github.ref == 'refs/heads/master' && 'master' || '' }}
|
||||
|
||||
permissions: {} # No permissions required
|
||||
|
||||
@@ -33,8 +31,7 @@ jobs:
|
||||
node-version: "lts/*"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
./scripts/layered.sh "$DEFAULT_BRANCH"
|
||||
run: "./scripts/layered.sh"
|
||||
|
||||
- name: Typecheck
|
||||
run: "yarn run lint:types"
|
||||
@@ -54,6 +51,7 @@ jobs:
|
||||
error|invalid_json
|
||||
error|misconfigured
|
||||
welcome_to_element
|
||||
devtools|settings|elementCallUrl
|
||||
|
||||
rethemendex_lint:
|
||||
name: "Rethemendex Check"
|
||||
|
||||
38
CHANGELOG.md
@@ -1,3 +1,41 @@
|
||||
Changes in [1.11.97](https://github.com/element-hq/element-web/releases/tag/v1.11.97) (2025-04-08)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
* New room list: reduce padding between avatar and room list border ([#29634](https://github.com/element-hq/element-web/pull/29634)). Contributed by @florianduros.
|
||||
* Bundle Element Call with Element Web packages ([#29309](https://github.com/element-hq/element-web/pull/29309)). Contributed by @t3chguy.
|
||||
* Hide an event notification if it is redacted ([#29605](https://github.com/element-hq/element-web/pull/29605)). Contributed by @Half-Shot.
|
||||
* Docker: Use nginx-unprivileged as base image ([#29353](https://github.com/element-hq/element-web/pull/29353)). Contributed by @AndrewFerr.
|
||||
* Switch away from nesting React trees and mangling the DOM ([#29586](https://github.com/element-hq/element-web/pull/29586)). Contributed by @t3chguy.
|
||||
* New room list: add notification decoration ([#29552](https://github.com/element-hq/element-web/pull/29552)). Contributed by @florianduros.
|
||||
* RoomListStore: Unread filter should match rooms that were marked as unread ([#29580](https://github.com/element-hq/element-web/pull/29580)). Contributed by @MidhunSureshR.
|
||||
* Add support for hiding videos ([#29496](https://github.com/element-hq/element-web/pull/29496)). Contributed by @Half-Shot.
|
||||
* Use an outline icon for the report room button ([#29573](https://github.com/element-hq/element-web/pull/29573)). Contributed by @robintown.
|
||||
* Generate/load pickle key on SSO ([#29568](https://github.com/element-hq/element-web/pull/29568)). Contributed by @Jujure.
|
||||
* Add report room dialog button/dialog. ([#29513](https://github.com/element-hq/element-web/pull/29513)). Contributed by @Half-Shot.
|
||||
* RoomListViewModel: Make the active room sticky in the list ([#29551](https://github.com/element-hq/element-web/pull/29551)). Contributed by @MidhunSureshR.
|
||||
* Replace checkboxes with Compound checkboxes, and appropriately label each checkbox. ([#29363](https://github.com/element-hq/element-web/pull/29363)). Contributed by @Half-Shot.
|
||||
* New room list: add selection decoration ([#29531](https://github.com/element-hq/element-web/pull/29531)). Contributed by @florianduros.
|
||||
* Simplified Sliding Sync ([#28515](https://github.com/element-hq/element-web/pull/28515)). Contributed by @dbkr.
|
||||
* Add ability to hide images after clicking "show image" ([#29467](https://github.com/element-hq/element-web/pull/29467)). Contributed by @Half-Shot.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
* Fix scroll issues in memberlist ([#29392](https://github.com/element-hq/element-web/pull/29392)). Contributed by @MidhunSureshR.
|
||||
* Ensure clicks on spoilers do not get handled by the hidden content ([#29618](https://github.com/element-hq/element-web/pull/29618)). Contributed by @t3chguy.
|
||||
* New room list: add cursor pointer on room list item ([#29627](https://github.com/element-hq/element-web/pull/29627)). Contributed by @florianduros.
|
||||
* Fix missing ambiguous url tooltips on Element Desktop ([#29619](https://github.com/element-hq/element-web/pull/29619)). Contributed by @t3chguy.
|
||||
* New room list: fix spacing and padding ([#29607](https://github.com/element-hq/element-web/pull/29607)). Contributed by @florianduros.
|
||||
* Make fetchdep check out matching branch name ([#29601](https://github.com/element-hq/element-web/pull/29601)). Contributed by @dbkr.
|
||||
* Fix MFileBody fileName not considering `filename` ([#29589](https://github.com/element-hq/element-web/pull/29589)). Contributed by @t3chguy.
|
||||
* Fix token expiry racing with login causing wrong error to be shown ([#29566](https://github.com/element-hq/element-web/pull/29566)). Contributed by @t3chguy.
|
||||
* Fix bug which caused startup to hang if the clock was wound back since a previous session ([#29558](https://github.com/element-hq/element-web/pull/29558)). Contributed by @richvdh.
|
||||
* RoomListViewModel: Reset any primary filter on secondary filter change ([#29562](https://github.com/element-hq/element-web/pull/29562)). Contributed by @MidhunSureshR.
|
||||
* RoomListStore: Unread filter should only filter rooms having unread counts ([#29555](https://github.com/element-hq/element-web/pull/29555)). Contributed by @MidhunSureshR.
|
||||
* In force-verify mode, prevent bypassing by cancelling device verification ([#29487](https://github.com/element-hq/element-web/pull/29487)). Contributed by @andybalaam.
|
||||
* Add title attribute to user identifier ([#29547](https://github.com/element-hq/element-web/pull/29547)). Contributed by @arpitbatra123.
|
||||
|
||||
|
||||
Changes in [1.11.96](https://github.com/element-hq/element-web/releases/tag/v1.11.96) (2025-03-25)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
12
Dockerfile
@@ -19,7 +19,10 @@ RUN /src/scripts/docker-package.sh
|
||||
RUN cp /src/config.sample.json /src/webapp/config.json
|
||||
|
||||
# App
|
||||
FROM nginx:alpine-slim
|
||||
FROM nginxinc/nginx-unprivileged:alpine-slim
|
||||
|
||||
# Need root user to install packages & manipulate the usr directory
|
||||
USER root
|
||||
|
||||
# Install jq and moreutils for sponge, both used by our entrypoints
|
||||
RUN apk add jq moreutils
|
||||
@@ -31,13 +34,6 @@ COPY --from=builder /src/webapp /app
|
||||
COPY /docker/nginx-templates/* /etc/nginx/templates/
|
||||
COPY /docker/docker-entrypoint.d/* /docker-entrypoint.d/
|
||||
|
||||
# Tell nginx to put its pidfile elsewhere, so it can run as non-root
|
||||
RUN sed -i -e 's,/var/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf
|
||||
|
||||
# nginx user must own the cache and etc directory to write cache and tweak the nginx config
|
||||
RUN chown -R nginx:0 /var/cache/nginx /etc/nginx
|
||||
RUN chmod -R g+w /var/cache/nginx /etc/nginx
|
||||
|
||||
RUN rm -rf /usr/share/nginx/html \
|
||||
&& ln -s /app /usr/share/nginx/html
|
||||
|
||||
|
||||
@@ -384,8 +384,6 @@ The VoIP and Jitsi options are:
|
||||
5. `audio_stream_url`: Optional URL to pass to Jitsi to enable live streaming. This option is considered experimental and may be removed
|
||||
at any time without notice.
|
||||
6. `element_call`: Optional configuration for native group calls using Element Call, with the following subkeys:
|
||||
- `url`: The URL of the Element Call instance to use for native group calls. This option is considered experimental
|
||||
and may be removed at any time without notice. Defaults to `https://call.element.io`.
|
||||
- `use_exclusively`: A boolean specifying whether Element Call should be used exclusively as the only VoIP stack in
|
||||
the app, removing the ability to start legacy 1:1 calls or Jitsi calls. Defaults to `false`.
|
||||
- `participant_limit`: The maximum number of users who can join a call; if
|
||||
|
||||
2
knip.ts
@@ -40,6 +40,8 @@ export default {
|
||||
// Used by webpack
|
||||
"process",
|
||||
"util",
|
||||
// Embedded into webapp
|
||||
"@element-hq/element-call-embedded",
|
||||
],
|
||||
ignoreBinaries: [
|
||||
// Used in scripts & workflows
|
||||
|
||||
13
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-web",
|
||||
"version": "1.11.96",
|
||||
"version": "1.11.97",
|
||||
"description": "Element: the future of secure communication",
|
||||
"author": "New Vector Ltd.",
|
||||
"repository": {
|
||||
@@ -65,7 +65,8 @@
|
||||
"test:playwright:screenshots": "playwright-screenshots --project=Chrome",
|
||||
"coverage": "yarn test --coverage",
|
||||
"analyse:webpack-bundles": "webpack-bundle-analyzer webpack-stats.json webapp",
|
||||
"update:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js"
|
||||
"update:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"resolutions": {
|
||||
"@playwright/test": "1.51.1",
|
||||
@@ -107,6 +108,7 @@
|
||||
"css-tree": "^3.0.0",
|
||||
"diff-dom": "^5.0.0",
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"domutils": "^3.2.2",
|
||||
"emojibase-regex": "15.3.2",
|
||||
"escape-html": "^1.0.3",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -115,12 +117,12 @@
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"highlight.js": "^11.3.1",
|
||||
"html-entities": "^2.0.0",
|
||||
"html-react-parser": "^5.2.2",
|
||||
"is-ip": "^3.1.0",
|
||||
"js-xxhash": "^4.0.0",
|
||||
"jsrsasign": "^11.0.0",
|
||||
"jszip": "^3.7.0",
|
||||
"katex": "^0.16.0",
|
||||
"linkify-element": "4.2.0",
|
||||
"linkify-react": "4.2.0",
|
||||
"linkify-string": "4.2.0",
|
||||
"linkifyjs": "4.2.0",
|
||||
@@ -128,7 +130,7 @@
|
||||
"maplibre-gl": "^5.0.0",
|
||||
"matrix-encrypt-attachment": "^1.0.3",
|
||||
"matrix-events-sdk": "0.0.1",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||
"matrix-js-sdk": "37.3.0",
|
||||
"matrix-widget-api": "^1.10.0",
|
||||
"memoize-one": "^6.0.0",
|
||||
"mime": "^4.0.4",
|
||||
@@ -144,6 +146,7 @@
|
||||
"react-blurhash": "^0.3.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-focus-lock": "^2.5.1",
|
||||
"react-string-replace": "^1.1.1",
|
||||
"react-transition-group": "^4.4.1",
|
||||
"react-virtualized": "^9.22.5",
|
||||
"rfc4648": "^1.4.0",
|
||||
@@ -177,6 +180,7 @@
|
||||
"@babel/preset-typescript": "^7.12.7",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@casualbot/jest-sonar-reporter": "2.2.7",
|
||||
"@element-hq/element-call-embedded": "0.9.0",
|
||||
"@element-hq/element-web-playwright-common": "^1.1.5",
|
||||
"@peculiar/webcrypto": "^1.4.3",
|
||||
"@playwright/test": "^1.50.1",
|
||||
@@ -263,6 +267,7 @@
|
||||
"minimist": "^1.2.6",
|
||||
"modernizr": "^3.12.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"patch-package": "^8.0.0",
|
||||
"playwright-core": "^1.51.0",
|
||||
"postcss": "8.4.46",
|
||||
"postcss-easings": "^4.0.0",
|
||||
|
||||
13
patches/@matrix-org+react-sdk-module-api+2.5.0.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/@matrix-org/react-sdk-module-api/lib/ModuleApi.d.ts b/node_modules/@matrix-org/react-sdk-module-api/lib/ModuleApi.d.ts
|
||||
index 917a7fc..a2710c6 100644
|
||||
--- a/node_modules/@matrix-org/react-sdk-module-api/lib/ModuleApi.d.ts
|
||||
+++ b/node_modules/@matrix-org/react-sdk-module-api/lib/ModuleApi.d.ts
|
||||
@@ -37,7 +37,7 @@ export interface ModuleApi {
|
||||
* @returns Whether the user submitted the dialog or closed it, and the model returned by the
|
||||
* dialog component if submitted.
|
||||
*/
|
||||
- openDialog<M extends object, P extends DialogProps = DialogProps, C extends DialogContent<P> = DialogContent<P>>(initialTitleOrOptions: string | ModuleUiDialogOptions, body: (props: P, ref: React.RefObject<C>) => React.ReactNode, props?: Omit<P, keyof DialogProps>): Promise<{
|
||||
+ openDialog<M extends object, P extends DialogProps = DialogProps, C extends DialogContent<P> = DialogContent<P>>(initialTitleOrOptions: string | ModuleUiDialogOptions, body: (props: P, ref: React.RefObject<C | null>) => React.ReactNode, props?: Omit<P, keyof DialogProps>): Promise<{
|
||||
didOkOrSubmit: boolean;
|
||||
model: M;
|
||||
}>;
|
||||
76
patches/@types+react+18.3.18.patch
Normal file
@@ -0,0 +1,76 @@
|
||||
diff --git a/node_modules/@types/react/index.d.ts b/node_modules/@types/react/index.d.ts
|
||||
index 6ea73ef..cb51757 100644
|
||||
--- a/node_modules/@types/react/index.d.ts
|
||||
+++ b/node_modules/@types/react/index.d.ts
|
||||
@@ -151,7 +151,7 @@ declare namespace React {
|
||||
/**
|
||||
* The current value of the ref.
|
||||
*/
|
||||
- readonly current: T | null;
|
||||
+ current: T;
|
||||
}
|
||||
|
||||
interface DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES {
|
||||
@@ -186,7 +186,7 @@ declare namespace React {
|
||||
* @see {@link RefObject}
|
||||
*/
|
||||
|
||||
- type Ref<T> = RefCallback<T> | RefObject<T> | null;
|
||||
+ type Ref<T> = RefCallback<T> | RefObject<T | null> | null;
|
||||
/**
|
||||
* A legacy implementation of refs where you can pass a string to a ref prop.
|
||||
*
|
||||
@@ -300,7 +300,7 @@ declare namespace React {
|
||||
*
|
||||
* @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
|
||||
*/
|
||||
- ref?: LegacyRef<T> | undefined;
|
||||
+ ref?: LegacyRef<T | null> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1234,7 +1234,7 @@ declare namespace React {
|
||||
*
|
||||
* @see {@link ForwardRefRenderFunction}
|
||||
*/
|
||||
- type ForwardedRef<T> = ((instance: T | null) => void) | MutableRefObject<T | null> | null;
|
||||
+ type ForwardedRef<T> = ((instance: T | null) => void) | RefObject<T | null> | null;
|
||||
|
||||
/**
|
||||
* The type of the function passed to {@link forwardRef}. This is considered different
|
||||
@@ -1565,7 +1565,7 @@ declare namespace React {
|
||||
[propertyName: string]: any;
|
||||
}
|
||||
|
||||
- function createRef<T>(): RefObject<T>;
|
||||
+ function createRef<T>(): RefObject<T | null>;
|
||||
|
||||
/**
|
||||
* The type of the component returned from {@link forwardRef}.
|
||||
@@ -1989,7 +1989,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T>(initialValue: T): MutableRefObject<T>;
|
||||
+ function useRef<T>(initialValue: T): RefObject<T>;
|
||||
// convenience overload for refs given as a ref prop as they typically start with a null value
|
||||
/**
|
||||
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
|
||||
@@ -2004,7 +2004,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T>(initialValue: T | null): RefObject<T>;
|
||||
+ function useRef<T>(initialValue: T | null): RefObject<T | null>;
|
||||
// convenience overload for potentially undefined initialValue / call with 0 arguments
|
||||
// has a default to stop it from defaulting to {} instead
|
||||
/**
|
||||
@@ -2017,7 +2017,7 @@ declare namespace React {
|
||||
* @version 16.8.0
|
||||
* @see {@link https://react.dev/reference/react/useRef}
|
||||
*/
|
||||
- function useRef<T = undefined>(initialValue?: undefined): MutableRefObject<T | undefined>;
|
||||
+ function useRef<T>(initialValue: T | undefined): RefObject<T | undefined>;
|
||||
/**
|
||||
* The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations.
|
||||
* Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside
|
||||
@@ -162,6 +162,7 @@ test.describe("Cryptography", function () {
|
||||
}
|
||||
|
||||
test("Can reset cross-signing keys", async ({ page, app, user: aliceCredentials }) => {
|
||||
await app.client.bootstrapCrossSigning(aliceCredentials);
|
||||
const secretStorageKey = await enableKeyBackup(app);
|
||||
|
||||
// Fetch the current cross-signing keys
|
||||
|
||||
@@ -27,16 +27,22 @@ test.use({
|
||||
test.describe("Dehydration", () => {
|
||||
test.skip(isDendrite, "does not yet support dehydration v2");
|
||||
|
||||
test("'Set up secure backup' creates dehydrated device", async ({ page, user, app }, workerInfo) => {
|
||||
// Create a backup (which will create SSSS, and dehydrated device)
|
||||
test("Verify device and reset creates dehydrated device", async ({ page, user, credentials, app }, workerInfo) => {
|
||||
// Verify the device by resetting the key (which will create SSSS, and dehydrated device)
|
||||
|
||||
const securityTab = await app.settings.openUserSettings("Security & Privacy");
|
||||
|
||||
await expect(securityTab.getByRole("heading", { name: "Secure Backup" })).toBeVisible();
|
||||
await expect(securityTab.getByText("Offline device enabled")).not.toBeVisible();
|
||||
await securityTab.getByRole("button", { name: "Set up", exact: true }).click();
|
||||
|
||||
await completeCreateSecretStorageDialog(page);
|
||||
await app.closeDialog();
|
||||
|
||||
// Verify the device by resetting the key
|
||||
const settings = await app.settings.openUserSettings("Encryption");
|
||||
await settings.getByRole("button", { name: "Verify this device" }).click();
|
||||
await page.getByRole("button", { name: "Proceed with reset" }).click();
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await page.getByRole("button", { name: "Copy" }).click();
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await page.getByRole("button", { name: "Done" }).click();
|
||||
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
|
||||
|
||||
@@ -292,17 +292,28 @@ export async function doTwoWaySasVerification(page: Page, verifier: JSHandle<Ver
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the security settings and enable secure key backup.
|
||||
*
|
||||
* Assumes that the current device has been cross-signed (which means that we skip a step where we set it up).
|
||||
* Open the encryption settings and enable key storage and recovery
|
||||
* Assumes that the current device has been verified
|
||||
*
|
||||
* Returns the recovery key
|
||||
*/
|
||||
export async function enableKeyBackup(app: ElementAppPage): Promise<string> {
|
||||
await app.settings.openUserSettings("Security & Privacy");
|
||||
await app.page.getByRole("button", { name: "Set up Secure Backup" }).click();
|
||||
const encryptionTab = await app.settings.openUserSettings("Encryption");
|
||||
|
||||
return await completeCreateSecretStorageDialog(app.page);
|
||||
const keyStorageToggle = encryptionTab.getByRole("checkbox", { name: "Allow key storage" });
|
||||
if (!(await keyStorageToggle.isChecked())) {
|
||||
await encryptionTab.getByRole("checkbox", { name: "Allow key storage" }).click();
|
||||
}
|
||||
|
||||
await encryptionTab.getByRole("button", { name: "Set up recovery" }).click();
|
||||
await encryptionTab.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
const recoveryKey = await encryptionTab.getByTestId("recoveryKey").innerText();
|
||||
await encryptionTab.getByRole("button", { name: "Continue" }).click();
|
||||
await encryptionTab.getByRole("textbox").fill(recoveryKey);
|
||||
await encryptionTab.getByRole("button", { name: "Finish set up" }).click();
|
||||
await app.settings.closeDialog();
|
||||
return recoveryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -165,6 +165,8 @@ test.describe("Room list", () => {
|
||||
test("should render an activity decoration", { tag: "@screenshot" }, async ({ page, app, user, bot }) => {
|
||||
const roomListView = getRoomList(page);
|
||||
|
||||
const otherRoomId = await app.client.createRoom({ name: "other room" });
|
||||
|
||||
const roomId = await app.client.createRoom({ name: "activity" });
|
||||
await app.client.inviteUser(roomId, bot.credentials.userId);
|
||||
await bot.joinRoom(roomId);
|
||||
@@ -178,6 +180,8 @@ test.describe("Room list", () => {
|
||||
await page.getByText("Show all activity in the room list (dots or number of unread messages)").click();
|
||||
await app.settings.closeDialog();
|
||||
|
||||
// Switch to the other room to avoid the notification to be cleared
|
||||
await app.viewRoomById(otherRoomId);
|
||||
await bot.sendMessage(roomId, "I am a robot. Beep.");
|
||||
|
||||
const room = roomListView.getByRole("gridcell", { name: "activity" });
|
||||
|
||||
@@ -28,7 +28,10 @@ test.describe("Preferences user settings tab", () => {
|
||||
const tab = await app.settings.openUserSettings("Preferences");
|
||||
// Assert that the top heading is rendered
|
||||
await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible();
|
||||
await expect(tab).toMatchScreenshot("Preferences-user-settings-tab-should-be-rendered-properly-1.png");
|
||||
await expect(tab).toMatchScreenshot("Preferences-user-settings-tab-should-be-rendered-properly-1.png", {
|
||||
// masked due to daylight saving time
|
||||
mask: [tab.locator("#mx_dropdownUserTimezone_value")],
|
||||
});
|
||||
});
|
||||
|
||||
test("should be able to change the app language", { tag: ["@no-firefox", "@no-webkit"] }, async ({ uut, user }) => {
|
||||
|
||||
@@ -1341,4 +1341,44 @@ test.describe("Timeline", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("spoilers", { tag: "@screenshot" }, () => {
|
||||
test("clicking a spoiler containing the pill de-spoilers on 1st click, then follows link on 2nd", async ({
|
||||
page,
|
||||
user,
|
||||
app,
|
||||
room,
|
||||
}) => {
|
||||
// View room
|
||||
await page.goto(`/#/room/${room.roomId}`);
|
||||
|
||||
// Send a spoilered pill
|
||||
await app.client.sendMessage(room.roomId, {
|
||||
msgtype: "m.text",
|
||||
body: user.userId,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: `<span data-mx-spoiler>https://matrix.to/#/${user.userId}</span>`,
|
||||
});
|
||||
|
||||
const screenshotOptions = {
|
||||
css: `
|
||||
.mx_MessageTimestamp {
|
||||
display: none !important;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const eventTile = page.locator(".mx_RoomView_body .mx_EventTile_last");
|
||||
await expect(eventTile).toMatchScreenshot("spoiler.png", screenshotOptions);
|
||||
|
||||
const rightPanelButton = page.getByText("Share profile");
|
||||
const pill = page.locator(".mx_UserPill");
|
||||
await pill.click({ force: true }); // force to click the spoiler wrapper instead
|
||||
await expect(eventTile).toMatchScreenshot("spoiler-uncovered.png", screenshotOptions);
|
||||
await expect(rightPanelButton).not.toBeVisible(); // assert the right panel is not yet open
|
||||
|
||||
await pill.click();
|
||||
await expect(rightPanelButton).toBeVisible(); // assert the right panel is open
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -114,7 +114,7 @@ export class ElementAppPage {
|
||||
* @param isRightPanel whether to select the right panel composer, otherwise the main timeline composer
|
||||
*/
|
||||
public getComposerField(isRightPanel?: boolean): Locator {
|
||||
return this.getComposer(isRightPanel).locator("[contenteditable]");
|
||||
return this.getComposer(isRightPanel).locator("div[contenteditable]");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 249 KiB After Width: | Height: | Size: 247 KiB |
BIN
playwright/snapshots/timeline/timeline.spec.ts/spoiler-linux.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import { SynapseContainer as BaseSynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers";
|
||||
|
||||
const TAG = "develop@sha256:4a66d4e3052740743f32648846a66c2517dd525fe8fd30db421a1c020b7e32e4";
|
||||
const TAG = "develop@sha256:66955f34a593cfc3b6e77b8d5510c60c6094f5bade8a17d2feaefbb8662ccf09";
|
||||
|
||||
/**
|
||||
* SynapseContainer which freezes the docker digest to stabilise tests,
|
||||
|
||||
@@ -16,18 +16,22 @@
|
||||
*/
|
||||
.mx_RoomListItemView {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--cpd-color-bg-action-secondary-hovered);
|
||||
|
||||
.mx_RoomListItemView_content {
|
||||
padding-right: var(--cpd-space-1-5x);
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RoomListItemView_container {
|
||||
padding-left: var(--cpd-space-3x);
|
||||
padding-left: var(--cpd-space-2x);
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
height: 100%;
|
||||
|
||||
.mx_RoomListItemView_content {
|
||||
padding-right: var(--cpd-space-3x);
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
/* The border is only under the room name and the future hover menu */
|
||||
@@ -46,8 +50,24 @@
|
||||
|
||||
.mx_RoomListItemView_menu_open {
|
||||
background-color: var(--cpd-color-bg-action-secondary-hovered);
|
||||
|
||||
.mx_RoomListItemView_content {
|
||||
padding-right: var(--cpd-space-1-5x);
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RoomListItemView_selected {
|
||||
background-color: var(--cpd-color-bg-action-secondary-pressed);
|
||||
}
|
||||
|
||||
.mx_RoomListItemView_notification_decoration {
|
||||
.mx_RoomListItemView_content {
|
||||
padding-right: var(--cpd-space-2x);
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RoomListItemView_empty {
|
||||
.mx_RoomListItemView_content {
|
||||
padding-right: var(--cpd-space-3x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,11 +816,13 @@ $left-gutter: 64px;
|
||||
.mx_EventTile_spoiler_content {
|
||||
filter: blur(5px) saturate(0.1) sepia(1);
|
||||
transition-duration: 0.5s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&.visible > .mx_EventTile_spoiler_content {
|
||||
filter: none;
|
||||
user-select: auto;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,10 +45,7 @@ getPRInfo() {
|
||||
|
||||
# Some CIs don't give us enough info, so we just get the PR number and ask the
|
||||
# GH API for more info - "fork:branch". Some give us this directly.
|
||||
if [ -n "$BUILDKITE_BRANCH" ]; then
|
||||
# BuildKite
|
||||
head=$BUILDKITE_BRANCH
|
||||
elif [ -n "$PR_NUMBER" ]; then
|
||||
if [ -n "$PR_NUMBER" ]; then
|
||||
# GitHub
|
||||
getPRInfo $PR_NUMBER
|
||||
elif [ -n "$REVIEW_ID" ]; then
|
||||
@@ -79,11 +76,14 @@ if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then
|
||||
clone $deforg $defrepo ${withoutPrefix%%/pr-*}
|
||||
fi
|
||||
|
||||
# Try the target branch of the push or PR.
|
||||
if [ -n "$GITHUB_BASE_REF" ]; then
|
||||
clone $deforg $defrepo $GITHUB_BASE_REF
|
||||
elif [ -n "$BUILDKITE_PULL_REQUEST_BASE_BRANCH" ]; then
|
||||
clone $deforg $defrepo $BUILDKITE_PULL_REQUEST_BASE_BRANCH
|
||||
# Try the target branch of the push or PR, or the branch that was pushed to
|
||||
# (ie. the 'master' branch should use matching 'master' dependencies)
|
||||
base_or_branch=$GITHUB_BASE_REF
|
||||
if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then
|
||||
base_or_branch=${GITHUB_REF}
|
||||
fi
|
||||
if [ -n "$base_or_branch" ]; then
|
||||
clone $deforg $defrepo $base_or_branch
|
||||
fi
|
||||
|
||||
# Try HEAD which is the branch name in Netlify (not BRANCH which is pull/xxxx/head for PR builds)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
set -ex
|
||||
|
||||
DEFAULT_BRANCH=${1:-develop}
|
||||
|
||||
# Creates a layered environment with the full repo for the app and SDKs cloned
|
||||
# and linked. This gives an element-web dev environment ready to build with
|
||||
# matching branches of react-sdk's dependencies so that changes can be tested
|
||||
@@ -23,7 +21,7 @@ export PR_ORG=element-hq
|
||||
export PR_REPO=element-web
|
||||
|
||||
# Set up the js-sdk first
|
||||
scripts/fetchdep.sh matrix-org matrix-js-sdk $DEFAULT_BRANCH
|
||||
scripts/fetchdep.sh matrix-org matrix-js-sdk develop
|
||||
pushd matrix-js-sdk
|
||||
[ -n "$JS_SDK_GITHUB_BASE_REF" ] && git fetch --depth 1 origin $JS_SDK_GITHUB_BASE_REF && git checkout $JS_SDK_GITHUB_BASE_REF
|
||||
yarn link
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type JSXElementConstructor } from "react";
|
||||
import { type JSX, type JSXElementConstructor } from "react";
|
||||
|
||||
export type { NonEmptyArray, XOR, Writeable } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
type SSOAction,
|
||||
encodeUnpaddedBase64,
|
||||
type OidcRegistrationClientMetadata,
|
||||
MatrixEventEvent,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
@@ -228,6 +229,16 @@ export default abstract class BasePlatform {
|
||||
window.focus();
|
||||
};
|
||||
|
||||
const closeHandler = (): void => notification.close();
|
||||
|
||||
// Clear a notification from a redacted event.
|
||||
if (ev) {
|
||||
ev.once(MatrixEventEvent.BeforeRedaction, closeHandler);
|
||||
notification.onclose = () => {
|
||||
ev.off(MatrixEventEvent.BeforeRedaction, closeHandler);
|
||||
};
|
||||
}
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type LegacyRef, type ReactNode } from "react";
|
||||
import React, { type JSX, type LegacyRef, type ReactNode } from "react";
|
||||
import sanitizeHtml, { type IOptions } from "sanitize-html";
|
||||
import classNames from "classnames";
|
||||
import katex from "katex";
|
||||
@@ -25,7 +25,7 @@ import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
|
||||
import { sanitizeHtmlParams, transformTags } from "./Linkify";
|
||||
import { graphemeSegmenter } from "./utils/strings";
|
||||
|
||||
export { Linkify, linkifyElement, linkifyAndSanitizeHtml } from "./Linkify";
|
||||
export { Linkify, linkifyAndSanitizeHtml } from "./Linkify";
|
||||
|
||||
// Anything outside the basic multilingual plane will be a surrogate pair
|
||||
const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/;
|
||||
@@ -365,53 +365,6 @@ function analyseEvent(content: IContent, highlights: Optional<string[]>, opts: E
|
||||
}
|
||||
}
|
||||
|
||||
export function bodyToDiv(
|
||||
content: IContent,
|
||||
highlights: Optional<string[]>,
|
||||
opts: EventRenderOpts = {},
|
||||
ref?: React.Ref<HTMLDivElement>,
|
||||
): ReactNode {
|
||||
const { strippedBody, formattedBody, emojiBodyElements, className } = bodyToNode(content, highlights, opts);
|
||||
|
||||
return formattedBody ? (
|
||||
<div
|
||||
key="body"
|
||||
ref={ref}
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{ __html: formattedBody }}
|
||||
dir="auto"
|
||||
/>
|
||||
) : (
|
||||
<div key="body" ref={ref} className={className} dir="auto">
|
||||
{emojiBodyElements || strippedBody}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function bodyToSpan(
|
||||
content: IContent,
|
||||
highlights: Optional<string[]>,
|
||||
opts: EventRenderOpts = {},
|
||||
ref?: React.Ref<HTMLSpanElement>,
|
||||
includeDir = true,
|
||||
): ReactNode {
|
||||
const { strippedBody, formattedBody, emojiBodyElements, className } = bodyToNode(content, highlights, opts);
|
||||
|
||||
return formattedBody ? (
|
||||
<span
|
||||
key="body"
|
||||
ref={ref}
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{ __html: formattedBody }}
|
||||
dir={includeDir ? "auto" : undefined}
|
||||
/>
|
||||
) : (
|
||||
<span key="body" ref={ref} className={className} dir={includeDir ? "auto" : undefined}>
|
||||
{emojiBodyElements || strippedBody}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
interface BodyToNodeReturn {
|
||||
strippedBody: string;
|
||||
formattedBody?: string;
|
||||
@@ -419,7 +372,11 @@ interface BodyToNodeReturn {
|
||||
className: string;
|
||||
}
|
||||
|
||||
function bodyToNode(content: IContent, highlights: Optional<string[]>, opts: EventRenderOpts = {}): BodyToNodeReturn {
|
||||
export function bodyToNode(
|
||||
content: IContent,
|
||||
highlights: Optional<string[]>,
|
||||
opts: EventRenderOpts = {},
|
||||
): BodyToNodeReturn {
|
||||
const eventInfo = analyseEvent(content, highlights, opts);
|
||||
|
||||
let emojiBody = false;
|
||||
|
||||
@@ -117,7 +117,6 @@ export interface IConfigOptions {
|
||||
obey_asserted_identity?: boolean; // MSC3086
|
||||
};
|
||||
element_call: {
|
||||
url?: string;
|
||||
guest_spa_url?: string;
|
||||
use_exclusively?: boolean;
|
||||
participant_limit?: number;
|
||||
|
||||
@@ -11,12 +11,7 @@ import sanitizeHtml, { type IOptions } from "sanitize-html";
|
||||
import { merge } from "lodash";
|
||||
import _Linkify from "linkify-react";
|
||||
|
||||
import {
|
||||
_linkifyElement,
|
||||
_linkifyString,
|
||||
ELEMENT_URL_PATTERN,
|
||||
options as linkifyMatrixOptions,
|
||||
} from "./linkify-matrix";
|
||||
import { _linkifyString, ELEMENT_URL_PATTERN, options as linkifyMatrixOptions } from "./linkify-matrix";
|
||||
import SettingsStore from "./settings/SettingsStore";
|
||||
import { tryTransformPermalinkToLocalHref } from "./utils/permalinks/Permalinks";
|
||||
import { mediaFromMxc } from "./customisations/Media";
|
||||
@@ -223,17 +218,6 @@ export function linkifyString(str: string, options = linkifyMatrixOptions): stri
|
||||
return _linkifyString(str, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linkifies the given DOM element. This is a wrapper around 'linkifyjs/element'.
|
||||
*
|
||||
* @param {object} element DOM element to linkify
|
||||
* @param {object} [options] Options for linkifyElement. Default: linkifyMatrixOptions
|
||||
* @returns {object}
|
||||
*/
|
||||
export function linkifyElement(element: HTMLElement, options = linkifyMatrixOptions): HTMLElement {
|
||||
return _linkifyElement(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linkify the given string and sanitize the HTML afterwards.
|
||||
*
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type Key, type MutableRefObject, type ReactElement, type RefCallback } from "react";
|
||||
import React, { type Key, type RefObject, type ReactElement, type RefCallback } from "react";
|
||||
|
||||
interface IChildProps {
|
||||
style: React.CSSProperties;
|
||||
@@ -20,7 +20,7 @@ interface IProps {
|
||||
// a list of state objects to apply to each child node in turn
|
||||
startStyles: React.CSSProperties[];
|
||||
|
||||
innerRef?: MutableRefObject<any>;
|
||||
innerRef?: RefObject<any>;
|
||||
}
|
||||
|
||||
function isReactElement(c: ReturnType<(typeof React.Children)["toArray"]>[number]): c is ReactElement {
|
||||
|
||||
@@ -30,7 +30,6 @@ export const DEFAULTS: DeepReadonly<IConfigOptions> = {
|
||||
preferred_domain: "meet.element.io",
|
||||
},
|
||||
element_call: {
|
||||
url: "https://call.element.io",
|
||||
use_exclusively: false,
|
||||
participant_limit: 8,
|
||||
brand: "Element Call",
|
||||
|
||||
@@ -354,7 +354,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({
|
||||
* nodeRef = inputRef when inputRef argument is provided.
|
||||
*/
|
||||
export const useRovingTabIndex = <T extends HTMLElement>(
|
||||
inputRef?: RefObject<T>,
|
||||
inputRef?: RefObject<T | null>,
|
||||
): [FocusHandler, boolean, RefCallback<T>, RefObject<T | null>] => {
|
||||
const context = useContext(RovingTabIndexContext);
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type RefObject } from "react";
|
||||
import React, { type JSX, type RefObject } from "react";
|
||||
|
||||
import AccessibleButton, { type ButtonProps } from "../../components/views/elements/AccessibleButton";
|
||||
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||
|
||||
type Props<T extends keyof HTMLElementTagNameMap> = Omit<ButtonProps<T>, "tabIndex"> & {
|
||||
inputRef?: RefObject<HTMLElementTagNameMap[T]>;
|
||||
inputRef?: RefObject<HTMLElementTagNameMap[T] | null>;
|
||||
focusOnMouseOver?: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type ReactElement, type RefCallback } from "react";
|
||||
import { type ReactElement, type RefCallback, type RefObject } from "react";
|
||||
|
||||
import type React from "react";
|
||||
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||
import { type FocusHandler, type Ref } from "./types";
|
||||
import { type FocusHandler } from "./types";
|
||||
|
||||
interface IProps {
|
||||
inputRef?: Ref;
|
||||
inputRef?: RefObject<HTMLElement | null>;
|
||||
children(renderProps: {
|
||||
onFocus: FocusHandler;
|
||||
isActive: boolean;
|
||||
|
||||
@@ -6,8 +6,4 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type RefObject } from "react";
|
||||
|
||||
export type Ref = RefObject<HTMLElement>;
|
||||
|
||||
export type FocusHandler = () => void;
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import { Text, Heading, Button, Separator } from "@vector-im/compound-web";
|
||||
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { MatrixClientPeg } from "../../../../MatrixClientPeg";
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { type JSX, createRef } from "react";
|
||||
import FileSaver from "file-saver";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type AuthDict } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
@@ -178,7 +178,9 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
type="password"
|
||||
disabled={disableForm}
|
||||
autoComplete="new-password"
|
||||
fieldRef={(field) => (this.fieldPassword = field)}
|
||||
fieldRef={(field) => {
|
||||
this.fieldPassword = field;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx_E2eKeysDialog_inputRow">
|
||||
@@ -195,7 +197,9 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
type="password"
|
||||
disabled={disableForm}
|
||||
autoComplete="new-password"
|
||||
fieldRef={(field) => (this.fieldPasswordConfirm = field)}
|
||||
fieldRef={(field) => {
|
||||
this.fieldPasswordConfirm = field;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { type HTMLAttributes, type ReactHTML, type ReactNode, type WheelEvent } from "react";
|
||||
import React, { type HTMLAttributes, type JSX, type ReactNode, type WheelEvent } from "react";
|
||||
|
||||
type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
|
||||
JSX.IntrinsicElements[T] extends HTMLAttributes<object> ? DynamicElementProps<T> : DynamicElementProps<"div">;
|
||||
@@ -27,10 +27,10 @@ export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<DynamicHtmlElem
|
||||
|
||||
export default class AutoHideScrollbar<T extends keyof JSX.IntrinsicElements> extends React.Component<IProps<T>> {
|
||||
public static defaultProps = {
|
||||
element: "div" as keyof ReactHTML,
|
||||
element: "div" as keyof HTMLElementTagNameMap,
|
||||
};
|
||||
|
||||
public readonly containerRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
public readonly containerRef = React.createRef<HTMLDivElement>();
|
||||
|
||||
public componentDidMount(): void {
|
||||
if (this.containerRef.current && this.props.onScroll) {
|
||||
|
||||
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type CSSProperties, type RefObject, type SyntheticEvent, useRef, useState } from "react";
|
||||
import React, { type JSX, type CSSProperties, type RefObject, type SyntheticEvent, useRef, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import classNames from "classnames";
|
||||
import FocusLock from "react-focus-lock";
|
||||
@@ -440,7 +440,7 @@ export default class ContextMenu extends React.PureComponent<React.PropsWithChil
|
||||
);
|
||||
}
|
||||
|
||||
public render(): React.ReactChild {
|
||||
public render(): JSX.Element {
|
||||
if (this.props.mountAsChild) {
|
||||
// Render as a child of the current parent
|
||||
return this.renderMenu();
|
||||
@@ -582,13 +582,15 @@ export const alwaysAboveRightOf = (
|
||||
|
||||
type ContextMenuTuple<T> = [
|
||||
boolean,
|
||||
RefObject<T>,
|
||||
RefObject<T | null>,
|
||||
(ev?: SyntheticEvent) => void,
|
||||
(ev?: SyntheticEvent) => void,
|
||||
(val: boolean) => void,
|
||||
];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
||||
export const useContextMenu = <T extends any = HTMLElement>(inputRef?: RefObject<T>): ContextMenuTuple<T> => {
|
||||
export const useContextMenu = <T extends HTMLElement = HTMLElement>(
|
||||
inputRef?: RefObject<T | null>,
|
||||
): ContextMenuTuple<T> => {
|
||||
let button = useRef<T>(null);
|
||||
if (inputRef) {
|
||||
// if we are given a ref, use it instead of ours
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { type FunctionComponent, type Key, type PropsWithChildren, type ReactNode } from "react";
|
||||
import React, { type JSX, type FunctionComponent, type Key, type PropsWithChildren, type ReactNode } from "react";
|
||||
|
||||
import { MenuItemRadio } from "../../accessibility/context_menu/MenuItemRadio";
|
||||
import { type ButtonEvent } from "../views/elements/AccessibleButton";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
|
||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { createRef, type JSX } from "react";
|
||||
|
||||
import AutoHideScrollbar, { type IProps as AutoHideScrollbarProps } from "./AutoHideScrollbar";
|
||||
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { createRef } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
|
||||
@@ -124,9 +124,9 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
public static displayName = "LoggedInView";
|
||||
|
||||
protected readonly _matrixClient: MatrixClient;
|
||||
protected readonly _roomView: React.RefObject<RoomView>;
|
||||
protected readonly _resizeContainer: React.RefObject<HTMLDivElement>;
|
||||
protected readonly resizeHandler: React.RefObject<HTMLDivElement>;
|
||||
protected readonly _roomView: React.RefObject<RoomView | null>;
|
||||
protected readonly _resizeContainer: React.RefObject<HTMLDivElement | null>;
|
||||
protected readonly resizeHandler: React.RefObject<HTMLDivElement | null>;
|
||||
protected layoutWatcherRef?: string;
|
||||
protected compactLayoutWatcherRef?: string;
|
||||
protected backgroundImageWatcherRef?: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import { type NumberSize, Resizable } from "re-resizable";
|
||||
import { type Direction } from "re-resizable/lib/resizer";
|
||||
import { type WebPanelResize } from "@matrix-org/analytics-events/types/typescript/WebPanelResize";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, lazy } from "react";
|
||||
import React, { type JSX, createRef, lazy } from "react";
|
||||
import {
|
||||
ClientEvent,
|
||||
createClient,
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type ReactNode, type TransitionEvent } from "react";
|
||||
import React, { type JSX, createRef, type ReactNode, type TransitionEvent } from "react";
|
||||
import classNames from "classnames";
|
||||
import {
|
||||
type Room,
|
||||
@@ -292,6 +292,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
|
||||
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
|
||||
this.readReceiptMap = {};
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
|
||||
@@ -800,7 +801,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
isRedacted={mxEv.isRedacted()}
|
||||
replacingEventId={mxEv.replacingEventId()}
|
||||
editState={isEditing ? this.props.editState : undefined}
|
||||
onHeightChanged={this.onHeightChanged}
|
||||
resizeObserver={this.resizeObserver}
|
||||
readReceipts={readReceipts}
|
||||
readReceiptMap={this.readReceiptMap}
|
||||
showUrlPreview={this.props.showUrlPreview}
|
||||
@@ -953,15 +954,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
this.eventTiles[eventId] = node;
|
||||
};
|
||||
|
||||
// once dynamic content in the events load, make the scrollPanel check the
|
||||
// scroll offsets.
|
||||
// Once dynamic content in the events load, make the scrollPanel check the scroll offsets.
|
||||
public onHeightChanged = (): void => {
|
||||
const scrollPanel = this.scrollPanel.current;
|
||||
if (scrollPanel) {
|
||||
scrollPanel.checkScroll();
|
||||
}
|
||||
this.scrollPanel.current?.checkScroll();
|
||||
};
|
||||
|
||||
private resizeObserver = new ResizeObserver(this.onHeightChanged);
|
||||
|
||||
private onTypingShown = (): void => {
|
||||
const scrollPanel = this.scrollPanel.current;
|
||||
// this will make the timeline grow, so checkScroll
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import NotificationsIcon from "@vector-im/compound-design-tokens/assets/web/icons/notifications";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { type JSX, createRef } from "react";
|
||||
|
||||
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
||||
import { lerp } from "../../utils/AnimationUtils";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type MutableRefObject, type ReactNode, useRef } from "react";
|
||||
import React, { type RefObject, type ReactNode, useRef } from "react";
|
||||
import { CallEvent, CallState, type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type Optional } from "matrix-events-sdk";
|
||||
@@ -34,7 +34,7 @@ const SHOW_CALL_IN_STATES = [
|
||||
];
|
||||
|
||||
interface IProps {
|
||||
movePersistedElement: MutableRefObject<(() => void) | undefined>;
|
||||
movePersistedElement: RefObject<(() => void) | null>;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -280,7 +280,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
export const PipContainer: React.FC = () => {
|
||||
const movePersistedElement = useRef<() => void>();
|
||||
const movePersistedElement = useRef<() => void>(null);
|
||||
|
||||
return <PipContainerInner movePersistedElement={movePersistedElement} />;
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import React, { type JSX, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
type ISearchResults,
|
||||
type IThreadBundledRelationship,
|
||||
@@ -59,7 +59,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
const aborted = useRef(false);
|
||||
// A map from room ID to permalink creator
|
||||
const permalinkCreators = useMemo(() => new Map<string, RoomPermalinkCreator>(), []);
|
||||
const innerRef = useRef<ScrollPanel | null>();
|
||||
const innerRef = useRef<ScrollPanel>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -198,12 +198,6 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
}
|
||||
}
|
||||
|
||||
// once dynamic content in the search results load, make the scrollPanel check
|
||||
// the scroll offsets.
|
||||
const onHeightChanged = (): void => {
|
||||
innerRef.current?.checkScroll();
|
||||
};
|
||||
|
||||
const onRef = (e: ScrollPanel | null): void => {
|
||||
if (typeof ref === "function") {
|
||||
ref(e);
|
||||
@@ -302,7 +296,6 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
searchHighlights={highlights ?? []}
|
||||
resultLink={resultLink}
|
||||
permalinkCreator={permalinkCreator}
|
||||
onHeightChanged={onHeightChanged}
|
||||
/>,
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import {
|
||||
ClientEvent,
|
||||
EventStatus,
|
||||
|
||||
@@ -256,7 +256,7 @@ interface LocalRoomViewProps {
|
||||
localRoom: LocalRoom;
|
||||
resizeNotifier: ResizeNotifier;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
roomView: RefObject<HTMLElement>;
|
||||
roomView: RefObject<HTMLElement | null>;
|
||||
onFileDrop: (dataTransfer: DataTransfer) => Promise<void>;
|
||||
mainSplitContentType: MainSplitContentType;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
type JSX,
|
||||
type Dispatch,
|
||||
type KeyboardEvent,
|
||||
type KeyboardEventHandler,
|
||||
@@ -636,7 +637,7 @@ const useIntersectionObserver = (callback: () => void): ((element: HTMLDivElemen
|
||||
}
|
||||
};
|
||||
|
||||
const observerRef = useRef<IntersectionObserver>();
|
||||
const observerRef = useRef<IntersectionObserver>(undefined);
|
||||
return (element: HTMLDivElement) => {
|
||||
if (observerRef.current) {
|
||||
observerRef.current.disconnect();
|
||||
|
||||
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
import { EventType, RoomType, JoinRule, Preset, type Room, RoomEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import React, { useCallback, useContext, useRef, useState } from "react";
|
||||
import React, { type JSX, useCallback, useContext, useRef, useState } from "react";
|
||||
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import createRoom, { type IOpts } from "../../createRoom";
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { type DetailedHTMLProps, type HTMLAttributes, type ReactNode } from "react";
|
||||
import React, { type JSX, type DetailedHTMLProps, type HTMLAttributes, type ReactNode } from "react";
|
||||
|
||||
interface Props extends DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> {
|
||||
className?: string;
|
||||
|
||||
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { _t, type TranslationKey } from "../../languageHandler";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type KeyboardEvent } from "react";
|
||||
import React, { type JSX, createRef, type KeyboardEvent } from "react";
|
||||
import {
|
||||
type Thread,
|
||||
THREAD_RELATION_TYPE,
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type ReactNode } from "react";
|
||||
import React, { type JSX, createRef, type ReactNode } from "react";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
@@ -81,7 +81,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
private dispatcherRef?: string;
|
||||
private themeWatcherRef?: string;
|
||||
private readonly dndWatcherRef?: string;
|
||||
private buttonRef: React.RefObject<HTMLButtonElement> = createRef();
|
||||
private buttonRef = createRef<HTMLButtonElement>();
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import SyntaxHighlight from "../views/elements/SyntaxHighlight";
|
||||
|
||||
@@ -21,7 +21,7 @@ import SdkConfig from "../../SdkConfig";
|
||||
import { useScopedRoomContext } from "../../contexts/ScopedRoomContext.tsx";
|
||||
|
||||
interface Props {
|
||||
roomView: RefObject<HTMLElement>;
|
||||
roomView: RefObject<HTMLElement | null>;
|
||||
resizeNotifier: ResizeNotifier;
|
||||
inviteEvent: MatrixEvent;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
import { LockSolidIcon, CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
@@ -388,7 +388,9 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
label={_td("auth|change_password_new_label")}
|
||||
value={this.state.password}
|
||||
minScore={PASSWORD_MIN_SCORE}
|
||||
fieldRef={(field) => (this.fieldPassword = field)}
|
||||
fieldRef={(field) => {
|
||||
this.fieldPassword = field;
|
||||
}}
|
||||
onChange={this.onInputChanged.bind(this, "password")}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
@@ -399,7 +401,9 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
labelInvalid={_td("auth|reset_password|passwords_mismatch")}
|
||||
value={this.state.password2}
|
||||
password={this.state.password}
|
||||
fieldRef={(field) => (this.fieldPasswordConfirm = field)}
|
||||
fieldRef={(field) => {
|
||||
this.fieldPasswordConfirm = field;
|
||||
}}
|
||||
onChange={this.onInputChanged.bind(this, "password2")}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type SSOFlow, SSOAction } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
SSOAction,
|
||||
type RegisterResponse,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import React, { Fragment, type ReactNode } from "react";
|
||||
import React, { type JSX, Fragment, type ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import SplashPage from "../SplashPage";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { type KeyBackupInfo, type VerificationRequest } from "matrix-js-sdk/src/crypto-api";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type SecretStorageKeyDescription } from "matrix-js-sdk/src/secret-storage";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ChangeEvent, type SyntheticEvent } from "react";
|
||||
import React, { type JSX, type ChangeEvent, type SyntheticEvent } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type Optional } from "matrix-events-sdk";
|
||||
import { type LoginFlow, MatrixError, SSOAction, type SSOFlow } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { Fragment, type PropsWithChildren, type ReactNode, useContext } from "react";
|
||||
import React, { type JSX, Fragment, type PropsWithChildren, type ReactNode, useContext } from "react";
|
||||
|
||||
import { AuthHeaderContext } from "./AuthHeaderContext";
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { isEqual } from "lodash";
|
||||
import React, { type ComponentProps, type PropsWithChildren, type Reducer, useReducer } from "react";
|
||||
import React, { type JSX, type ComponentProps, type PropsWithChildren, type Reducer, useReducer } from "react";
|
||||
|
||||
import { AuthHeaderContext } from "./AuthHeaderContext";
|
||||
import { type AuthHeaderModifier } from "./AuthHeaderModifier";
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { useMemo } from "react";
|
||||
import React, { type JSX, useMemo } from "react";
|
||||
|
||||
type FlexProps = {
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { type ComponentProps, type JSXElementConstructor, useMemo } from "react";
|
||||
import React, { type JSX, type ComponentProps, type JSXElementConstructor, useMemo } from "react";
|
||||
|
||||
type FlexProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = {
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type ReactNode, type RefObject } from "react";
|
||||
import React, { createRef, type ReactNode } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { type Playback, type PlaybackState } from "../../../audio/Playback";
|
||||
@@ -31,8 +31,8 @@ interface IState {
|
||||
}
|
||||
|
||||
export default abstract class AudioPlayerBase<T extends IProps = IProps> extends React.PureComponent<T, IState> {
|
||||
protected seekRef: RefObject<SeekBar> = createRef();
|
||||
protected playPauseRef: RefObject<PlayPauseButton> = createRef();
|
||||
protected seekRef = createRef<SeekBar>();
|
||||
protected playPauseRef = createRef<PlayPauseButton>();
|
||||
|
||||
public constructor(props: T) {
|
||||
super(props);
|
||||
|
||||
@@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { type PropsWithChildren } from "react";
|
||||
import React, { type JSX, type PropsWithChildren } from "react";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ReactElement } from "react";
|
||||
import React, { type JSX, type ReactElement } from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { type JSX, createRef } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ComponentProps, PureComponent, type RefCallback, type RefObject } from "react";
|
||||
import React, { type ComponentProps, PureComponent, type Ref } from "react";
|
||||
|
||||
import Field, { type IInputProps } from "../elements/Field";
|
||||
import { _t, _td, type TranslationKey } from "../../../languageHandler";
|
||||
@@ -15,7 +15,7 @@ import * as Email from "../../../email";
|
||||
|
||||
interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
|
||||
id?: string;
|
||||
fieldRef?: RefCallback<Field> | RefObject<Field>;
|
||||
fieldRef?: Ref<Field>;
|
||||
value: string;
|
||||
autoFocus?: boolean;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import classNames from "classnames";
|
||||
import { type InternationalisedPolicy, type Terms, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { AuthType, type AuthDict, type IInputs, type IStageStatus } from "matrix-js-sdk/src/interactive-auth";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import React, { type ChangeEvent, createRef, type FormEvent, Fragment } from "react";
|
||||
import React, { type JSX, type ChangeEvent, createRef, type FormEvent, Fragment } from "react";
|
||||
import { Button, Text } from "@vector-im/compound-web";
|
||||
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import { getCurrentLanguage } from "../../../languageHandler";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type ReactNode } from "react";
|
||||
import React, { type JSX, createRef, type ReactNode } from "react";
|
||||
import { ClientRendezvousFailureReason, MSC4108FailureReason } from "matrix-js-sdk/src/rendezvous";
|
||||
import ChevronLeftIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-left";
|
||||
import CheckCircleSolidIcon from "@vector-im/compound-design-tokens/assets/web/icons/check-circle-solid";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ComponentProps, PureComponent, type RefCallback, type RefObject } from "react";
|
||||
import React, { type ComponentProps, PureComponent, type Ref } from "react";
|
||||
|
||||
import Field, { type IInputProps } from "../elements/Field";
|
||||
import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation";
|
||||
@@ -14,7 +14,7 @@ import { _t, _td, type TranslationKey } from "../../../languageHandler";
|
||||
|
||||
interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> {
|
||||
id?: string;
|
||||
fieldRef?: RefCallback<Field> | RefObject<Field>;
|
||||
fieldRef?: Ref<Field>;
|
||||
autoComplete?: string;
|
||||
value: string;
|
||||
password: string; // The password we're confirming
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ComponentProps, PureComponent, type RefCallback, type RefObject } from "react";
|
||||
import React, { type ComponentProps, PureComponent, type Ref } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import type { ZxcvbnResult } from "@zxcvbn-ts/core";
|
||||
@@ -22,7 +22,7 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
|
||||
className?: string;
|
||||
minScore: 0 | 1 | 2 | 3 | 4;
|
||||
value: string;
|
||||
fieldRef?: RefCallback<Field> | RefObject<Field>;
|
||||
fieldRef?: Ref<Field>;
|
||||
// Additional strings such as a username used to catch bad passwords
|
||||
userInputs?: string[];
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type SyntheticEvent } from "react";
|
||||
import React, { type JSX, type SyntheticEvent } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
@@ -427,7 +427,9 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||
disabled={this.props.busy}
|
||||
autoFocus={autoFocusPassword}
|
||||
onValidate={this.onPasswordValidate}
|
||||
ref={(field) => (this[LoginField.Password] = field)}
|
||||
ref={(field) => {
|
||||
this[LoginField.Password] = field;
|
||||
}}
|
||||
/>
|
||||
{forgotPasswordJsx}
|
||||
{!this.props.busy && (
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type BaseSyntheticEvent, type ComponentProps, type ReactNode } from "react";
|
||||
import React, { type JSX, type BaseSyntheticEvent, type ComponentProps, type ReactNode } from "react";
|
||||
import { type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
@@ -456,7 +456,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||
: _td("auth|registration|continue_without_email_field_label");
|
||||
return (
|
||||
<EmailField
|
||||
fieldRef={(field) => (this[RegistrationField.Email] = field)}
|
||||
fieldRef={(field) => {
|
||||
this[RegistrationField.Email] = field;
|
||||
}}
|
||||
label={emailLabel}
|
||||
value={this.state.email}
|
||||
validationRules={this.validateEmailRules.bind(this)}
|
||||
@@ -471,7 +473,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||
return (
|
||||
<PassphraseField
|
||||
id="mx_RegistrationForm_password"
|
||||
fieldRef={(field) => (this[RegistrationField.Password] = field)}
|
||||
fieldRef={(field) => {
|
||||
this[RegistrationField.Password] = field;
|
||||
}}
|
||||
minScore={PASSWORD_MIN_SCORE}
|
||||
value={this.state.password}
|
||||
onChange={this.onPasswordChange}
|
||||
@@ -486,7 +490,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||
return (
|
||||
<PassphraseConfirmField
|
||||
id="mx_RegistrationForm_passwordConfirm"
|
||||
fieldRef={(field) => (this[RegistrationField.PasswordConfirm] = field)}
|
||||
fieldRef={(field) => {
|
||||
this[RegistrationField.PasswordConfirm] = field;
|
||||
}}
|
||||
autoComplete="new-password"
|
||||
value={this.state.passwordConfirm}
|
||||
password={this.state.password}
|
||||
@@ -514,7 +520,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||
);
|
||||
return (
|
||||
<Field
|
||||
ref={(field) => (this[RegistrationField.PhoneNumber] = field)}
|
||||
ref={(field) => {
|
||||
this[RegistrationField.PhoneNumber] = field;
|
||||
}}
|
||||
type="text"
|
||||
label={phoneLabel}
|
||||
value={this.state.phoneNumber}
|
||||
@@ -529,7 +537,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||
return (
|
||||
<Field
|
||||
id="mx_RegistrationForm_username"
|
||||
ref={(field) => (this[RegistrationField.Username] = field)}
|
||||
ref={(field) => {
|
||||
this[RegistrationField.Username] = field;
|
||||
}}
|
||||
type="text"
|
||||
autoFocus={true}
|
||||
label={_t("common|username")}
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import classNames from "classnames";
|
||||
import {
|
||||
EventType,
|
||||
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { forwardRef, type ReactNode, type Ref, useContext } from "react";
|
||||
import React, { type JSX, forwardRef, type ReactNode, type Ref, useContext } from "react";
|
||||
import { type RoomMember, type ResizeMethod } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { type JSX } from "react";
|
||||
import { type RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import emailPillAvatar from "../../../../res/img/icon-email-pill-avatar.svg";
|
||||
|
||||