Add lint rule to protect against this access on unbound methods (#32578)

* Add Actions to ViewModel utility types and specify `this: void` signature

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add https://typescript-eslint.io/rules/unbound-method/ linter to shared-components

also fix stray lint config which doesn't apply to SC

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add https://typescript-eslint.io/rules/unbound-method/ linter to element-web

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix genuine issues identified by the linter

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Specify this:void on i18napi

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update Module API

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add comment for MapToVoidThis

Added utility type to map VM actions to unbound functions.

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2026-02-23 15:37:58 +00:00
committed by GitHub
parent 87b28b725c
commit 77670eb369
135 changed files with 285 additions and 263 deletions
+2
View File
@@ -199,6 +199,7 @@ module.exports = {
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "playwright/**/*.ts", "*.ts"], files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "playwright/**/*.ts", "*.ts"],
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"], extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
rules: { rules: {
"@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
"@typescript-eslint/explicit-function-return-type": [ "@typescript-eslint/explicit-function-return-type": [
"error", "error",
{ {
@@ -238,6 +239,7 @@ module.exports = {
"@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off", "@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/no-empty-object-type": "off", "@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/unbound-method": "off",
// Jest/Playwright specific // Jest/Playwright specific
+1 -1
View File
@@ -47,7 +47,7 @@ interface FooViewActions {
// ViewModel is an object (usually a class) that implements both the interfaces listed above. // ViewModel is an object (usually a class) that implements both the interfaces listed above.
// https://github.com/element-hq/element-web/blob/develop/packages/shared-components/src/ViewModel.ts // https://github.com/element-hq/element-web/blob/develop/packages/shared-components/src/ViewModel.ts
export type FooViewModel = ViewModel<FooViewSnapshot> & FooViewActions; export type FooViewModel = ViewModel<FooViewSnapshot, FooViewActions>;
interface FooViewProps { interface FooViewProps {
// Ideally the view only depends on the view model i.e you don't expect any other props here. // Ideally the view only depends on the view model i.e you don't expect any other props here.
+26 -27
View File
@@ -9,9 +9,10 @@ module.exports = {
root: true, root: true,
plugins: ["matrix-org", "eslint-plugin-react-compiler"], plugins: ["matrix-org", "eslint-plugin-react-compiler"],
extends: [ extends: [
"plugin:matrix-org/babel",
"plugin:matrix-org/react", "plugin:matrix-org/react",
"plugin:matrix-org/a11y", "plugin:matrix-org/a11y",
"plugin:matrix-org/typescript",
"plugin:matrix-org/react",
"plugin:storybook/recommended", "plugin:storybook/recommended",
], ],
parserOptions: { parserOptions: {
@@ -42,37 +43,35 @@ module.exports = {
], ],
}, },
], ],
"@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
"@typescript-eslint/explicit-function-return-type": [
"error",
{
allowExpressions: true,
},
],
// We're okay being explicit at the moment
// "@typescript-eslint/no-empty-interface": "off",
// We'd rather not do this but we do
// "@typescript-eslint/ban-ts-comment": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-empty-object-type": [
"error",
{
// We do this sometimes to brand interfaces
allowInterfaces: "with-single-extends",
},
],
}, },
overrides: [ overrides: [
{ {
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}"], files: ["src/**/*.test.{ts,tsx}"],
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
rules: { rules: {
"@typescript-eslint/explicit-function-return-type": [ "@typescript-eslint/unbound-method": "off",
"error",
{
allowExpressions: true,
},
],
// Remove Babel things manually due to override limitations
"@babel/no-invalid-this": ["off"],
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
"@typescript-eslint/ban-ts-comment": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-empty-object-type": [
"error",
{
// We do this sometimes to brand interfaces
allowInterfaces: "with-single-extends",
},
],
}, },
}, },
], ],
@@ -70,7 +70,7 @@ export interface AudioPlayerViewActions {
/** /**
* The view model for the audio player. * The view model for the audio player.
*/ */
export type AudioPlayerViewModel = ViewModel<AudioPlayerViewSnapshot> & AudioPlayerViewActions; export type AudioPlayerViewModel = ViewModel<AudioPlayerViewSnapshot, AudioPlayerViewActions>;
interface AudioPlayerViewProps { interface AudioPlayerViewProps {
/** /**
@@ -84,7 +84,7 @@ interface DecryptionFailureBodyViewProps {
/** /**
* React ref to attach to any React components returned * React ref to attach to any React components returned
*/ */
ref?: React.RefObject<any>; ref?: React.RefObject<HTMLDivElement>;
} }
/** /**
@@ -57,8 +57,10 @@ export interface DisambiguatedProfileViewActions {
/** /**
* The view model for DisambiguatedProfileView. * The view model for DisambiguatedProfileView.
*/ */
export type DisambiguatedProfileViewModel = ViewModel<DisambiguatedProfileViewSnapshot> & export type DisambiguatedProfileViewModel = ViewModel<
DisambiguatedProfileViewActions; DisambiguatedProfileViewSnapshot,
DisambiguatedProfileViewActions
>;
interface DisambiguatedProfileViewProps { interface DisambiguatedProfileViewProps {
/** /**
@@ -89,7 +89,7 @@ export interface WidgetContextMenuAction {
onMoveButton: (direction: number) => void; onMoveButton: (direction: number) => void;
} }
export type WidgetContextMenuViewModel = ViewModel<WidgetContextMenuSnapshot> & WidgetContextMenuAction; export type WidgetContextMenuViewModel = ViewModel<WidgetContextMenuSnapshot, WidgetContextMenuAction>;
interface WidgetContextMenuViewProps { interface WidgetContextMenuViewProps {
vm: WidgetContextMenuViewModel; vm: WidgetContextMenuViewModel;
@@ -103,7 +103,7 @@ export interface RoomListHeaderViewActions {
/** /**
* The view model for the room list header component. * The view model for the room list header component.
*/ */
export type RoomListHeaderViewModel = ViewModel<RoomListHeaderViewSnapshot> & RoomListHeaderViewActions; export type RoomListHeaderViewModel = ViewModel<RoomListHeaderViewSnapshot, RoomListHeaderViewActions>;
interface RoomListHeaderViewProps { interface RoomListHeaderViewProps {
/** /**
@@ -25,7 +25,7 @@ import type { RoomListItemSnapshot, RoomListItemActions } from "./RoomListItemVi
/** /**
* View model type for room list item * View model type for room list item
*/ */
export type RoomItemViewModel = ViewModel<RoomListItemSnapshot> & RoomListItemActions; export type RoomItemViewModel = ViewModel<RoomListItemSnapshot, RoomListItemActions>;
/** /**
* Props for RoomListItemMoreOptionsMenu component * Props for RoomListItemMoreOptionsMenu component
@@ -21,7 +21,7 @@ import type { RoomListItemSnapshot, RoomListItemActions } from "./RoomListItemVi
/** /**
* View model type for room list item * View model type for room list item
*/ */
export type RoomItemViewModel = ViewModel<RoomListItemSnapshot> & RoomListItemActions; export type RoomItemViewModel = ViewModel<RoomListItemSnapshot, RoomListItemActions>;
/** /**
* Props for RoomListItemNotificationMenu component * Props for RoomListItemNotificationMenu component
@@ -105,7 +105,7 @@ export interface RoomListItemActions {
/** /**
* The view model type for a room list item * The view model type for a room list item
*/ */
export type RoomItemViewModel = ViewModel<RoomListItemSnapshot> & RoomListItemActions; export type RoomItemViewModel = ViewModel<RoomListItemSnapshot, RoomListItemActions>;
/** /**
* Props for RoomListItemView component * Props for RoomListItemView component
@@ -50,7 +50,7 @@ export interface RoomListSearchViewActions {
/** /**
* The view model for the room list search component. * The view model for the room list search component.
*/ */
export type RoomListSearchViewModel = ViewModel<RoomListSearchViewSnapshot> & RoomListSearchViewActions; export type RoomListSearchViewModel = ViewModel<RoomListSearchViewSnapshot, RoomListSearchViewActions>;
interface RoomListSearchViewProps { interface RoomListSearchViewProps {
/** /**
@@ -12,7 +12,7 @@ import { RoomListPrimaryFilters, type FilterId } from "../RoomListPrimaryFilters
import { RoomListLoadingSkeleton } from "./RoomListLoadingSkeleton"; import { RoomListLoadingSkeleton } from "./RoomListLoadingSkeleton";
import { RoomListEmptyStateView } from "./RoomListEmptyStateView"; import { RoomListEmptyStateView } from "./RoomListEmptyStateView";
import { VirtualizedRoomListView, type RoomListViewState } from "../VirtualizedRoomListView"; import { VirtualizedRoomListView, type RoomListViewState } from "../VirtualizedRoomListView";
import { type Room } from "../RoomListItemView"; import { type Room, type RoomItemViewModel } from "../RoomListItemView";
/** /**
* Snapshot for the room list view * Snapshot for the room list view
@@ -49,7 +49,7 @@ export interface RoomListViewActions {
/** Called to create a new room */ /** Called to create a new room */
createRoom: () => void; createRoom: () => void;
/** Get view model for a specific room (virtualization API) */ /** Get view model for a specific room (virtualization API) */
getRoomItemViewModel: (roomId: string) => any; getRoomItemViewModel: (roomId: string) => RoomItemViewModel;
/** Called when the visible range changes (virtualization API) */ /** Called when the visible range changes (virtualization API) */
updateVisibleRooms: (startIndex: number, endIndex: number) => void; updateVisibleRooms: (startIndex: number, endIndex: number) => void;
} }
@@ -57,7 +57,7 @@ export interface RoomListViewActions {
/** /**
* The view model type for the room list view * The view model type for the room list view
*/ */
export type RoomListViewModel = ViewModel<RoomListSnapshot> & RoomListViewActions; export type RoomListViewModel = ViewModel<RoomListSnapshot, RoomListViewActions>;
/** /**
* Props for RoomListView component * Props for RoomListView component
@@ -8,7 +8,7 @@
import React from "react"; import React from "react";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import { type Room, type RoomListItemSnapshot, RoomNotifState } from "./RoomListItemView"; import { type Room, type RoomItemViewModel, type RoomListItemSnapshot, RoomNotifState } from "./RoomListItemView";
/** /**
* Mock avatar component for stories * Mock avatar component for stories
@@ -39,6 +39,7 @@ export const mockAvatar = (name: string): React.ReactElement => (
*/ */
export const renderAvatar = (room: Room): React.ReactElement => { export const renderAvatar = (room: Room): React.ReactElement => {
// Cast to any to access properties - in real usage, the room object from the SDK will have these // Cast to any to access properties - in real usage, the room object from the SDK will have these
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return mockAvatar((room as any)?.name || "Room"); return mockAvatar((room as any)?.name || "Room");
}; };
@@ -102,8 +103,8 @@ export const createMockRoomSnapshot = (id: string, name: string, index: number):
/** /**
* Create a mock getRoomItemViewModel function for stories * Create a mock getRoomItemViewModel function for stories
*/ */
export const createGetRoomItemViewModel = (roomIds: string[]): ((roomId: string) => any) => { export const createGetRoomItemViewModel = (roomIds: string[]): ((roomId: string) => RoomItemViewModel) => {
const viewModels = new Map(); const viewModels = new Map<string, RoomItemViewModel>();
roomIds.forEach((roomId, index) => { roomIds.forEach((roomId, index) => {
const name = roomNames[index % roomNames.length]; const name = roomNames[index % roomNames.length];
const snapshot = createMockRoomSnapshot(roomId, name, index); const snapshot = createMockRoomSnapshot(roomId, name, index);
@@ -125,7 +126,7 @@ export const createGetRoomItemViewModel = (roomIds: string[]): ((roomId: string)
viewModels.set(roomId, mockViewModel); viewModels.set(roomId, mockViewModel);
}); });
return (roomId: string) => viewModels.get(roomId); return (roomId: string) => viewModels.get(roomId)!;
}; };
/** /**
@@ -100,7 +100,7 @@ export type RoomStatusBarViewSnapshot =
/** /**
* The view model for RoomStatusBarView. * The view model for RoomStatusBarView.
*/ */
export type RoomStatusBarViewModel = ViewModel<RoomStatusBarViewSnapshot> & RoomStatusBarViewActions; export type RoomStatusBarViewModel = ViewModel<RoomStatusBarViewSnapshot, RoomStatusBarViewActions>;
interface RoomStatusBarViewProps { interface RoomStatusBarViewProps {
/** /**
@@ -55,7 +55,7 @@ export function Box({
...props ...props
}: React.PropsWithChildren<BoxProps>): JSX.Element { }: React.PropsWithChildren<BoxProps>): JSX.Element {
const style = useMemo(() => { const style = useMemo(() => {
const style: Record<string, any> = {}; const style: Record<string, string> = {};
if (flex) style["--mx-box-flex"] = flex; if (flex) style["--mx-box-flex"] = flex;
if (shrink) style["--mx-box-shrink"] = shrink; if (shrink) style["--mx-box-shrink"] = shrink;
if (grow) style["--mx-box-grow"] = grow; if (grow) style["--mx-box-grow"] = grow;
@@ -11,6 +11,7 @@ import React, { type JSX, type ComponentProps, type JSXElementConstructor, useMe
import styles from "./Flex.module.css"; import styles from "./Flex.module.css";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FlexProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = { type FlexProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = {
/** /**
* The type of the HTML element * The type of the HTML element
@@ -60,6 +61,7 @@ type FlexProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any
/** /**
* A flexbox container helper * A flexbox container helper
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function Flex<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "div">({ export function Flex<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "div">({
as = "div", as = "div",
display = "flex", display = "flex",
@@ -21,7 +21,7 @@ export class I18nApi implements II18nApi {
/** /**
* Register translations for the module, may override app's existing translations * Register translations for the module, may override app's existing translations
*/ */
public register(translations: Partial<Translations>): void { public register(this: void, translations: Partial<Translations>): void {
const langs: Record<string, Record<string, string>> = {}; const langs: Record<string, Record<string, string>> = {};
for (const key in translations) { for (const key in translations) {
@@ -42,11 +42,9 @@ export class I18nApi implements II18nApi {
* @param key - The key to translate * @param key - The key to translate
* @param variables - Optional variables to interpolate into the translation * @param variables - Optional variables to interpolate into the translation
*/ */
public translate(key: TranslationKey, variables?: Variables): string { public translate(this: void, key: TranslationKey, variables?: Variables): string {
return _t(key, variables); return _t(key, variables);
} }
public humanizeTime(timeMillis: number): string { public humanizeTime = (timeMillis: number): string => humanizeTime(timeMillis, this);
return humanizeTime(timeMillis, this);
}
} }
@@ -113,7 +113,7 @@ export interface IVirtualizedListProps<Item, Context> extends Omit<
/** /**
* Utility type for the prop scrollIntoViewOnChange allowing it to be memoised by a caller without repeating types * Utility type for the prop scrollIntoViewOnChange allowing it to be memoised by a caller without repeating types
*/ */
export type ScrollIntoViewOnChange<Item, Context = any> = NonNullable< export type ScrollIntoViewOnChange<Item, Context> = NonNullable<
VirtuosoProps<Item, VirtualizedListContext<Context>>["scrollIntoViewOnChange"] VirtuosoProps<Item, VirtualizedListContext<Context>>["scrollIntoViewOnChange"]
>; >;
@@ -124,7 +124,7 @@ export type ScrollIntoViewOnChange<Item, Context = any> = NonNullable<
* @template Item - The type of data items in the list * @template Item - The type of data items in the list
* @template Context - The type of additional context data passed to items * @template Context - The type of additional context data passed to items
*/ */
export function VirtualizedList<Item, Context = any>(props: IVirtualizedListProps<Item, Context>): React.ReactElement { export function VirtualizedList<Item, Context>(props: IVirtualizedListProps<Item, Context>): React.ReactElement {
// Extract our custom props to avoid conflicts with Virtuoso props // Extract our custom props to avoid conflicts with Virtuoso props
const { const {
items, items,
@@ -9,15 +9,22 @@ Please see LICENSE files in the repository root for full details.
* The interface for a generic View Model passed to the shared components. * The interface for a generic View Model passed to the shared components.
* The snapshot is of type T which is a type specifying a snapshot for the view in question. * The snapshot is of type T which is a type specifying a snapshot for the view in question.
*/ */
export interface ViewModel<T> {
// Utility type to map all VM actions to unbound functions so that they do not have
// to be called with the correct 'this' context. This prevents "cannot read X of undefined" bugs.
type MapToVoidThis<T> = {
[K in keyof T]: T[K] extends (...args: infer A) => infer R ? (this: void, ...args: A) => R : T[K];
};
export type ViewModel<Snapshot, Actions = unknown> = {
/** /**
* The current snapshot of the view model. * The current snapshot of the view model.
*/ */
getSnapshot: () => T; getSnapshot: () => Snapshot;
/** /**
* Subscribes to changes in the view model. * Subscribes to changes in the view model.
* The listener will be called whenever the snapshot changes. * The listener will be called whenever the snapshot changes.
*/ */
subscribe: (listener: () => void) => () => void; subscribe: (listener: () => void) => () => void;
} } & MapToVoidThis<Actions>;
@@ -14,7 +14,7 @@ import { type ViewModel } from "./ViewModel";
* @param vm The view model to use * @param vm The view model to use
* @returns The current snapshot * @returns The current snapshot
*/ */
export function useViewModel<T>(vm: ViewModel<T>): T { export function useViewModel<T>(vm: ViewModel<T, unknown>): T {
// We need to pass the same getSnapshot function as getServerSnapshot as this // We need to pass the same getSnapshot function as getServerSnapshot as this
// is used when making the HTML chat export. // is used when making the HTML chat export.
return useSyncExternalStore(vm.subscribe, vm.getSnapshot, vm.getSnapshot); return useSyncExternalStore(vm.subscribe, vm.getSnapshot, vm.getSnapshot);
+10 -10
View File
@@ -7,8 +7,8 @@ settings:
catalogs: catalogs:
default: default:
'@element-hq/element-web-module-api': '@element-hq/element-web-module-api':
specifier: 1.9.0 specifier: 1.9.1
version: 1.9.0 version: 1.9.1
'@element-hq/element-web-playwright-common': '@element-hq/element-web-playwright-common':
specifier: 2.2.7 specifier: 2.2.7
version: 2.2.7 version: 2.2.7
@@ -91,7 +91,7 @@ importers:
version: 7.28.6 version: 7.28.6
'@element-hq/element-web-module-api': '@element-hq/element-web-module-api':
specifier: 'catalog:' specifier: 'catalog:'
version: 1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4) version: 1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
'@element-hq/web-shared-components': '@element-hq/web-shared-components':
specifier: workspace:* specifier: workspace:*
version: link:packages/shared-components version: link:packages/shared-components
@@ -371,7 +371,7 @@ importers:
version: 0.16.3 version: 0.16.3
'@element-hq/element-web-playwright-common': '@element-hq/element-web-playwright-common':
specifier: 'catalog:' specifier: 'catalog:'
version: 2.2.7(@element-hq/element-web-module-api@1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2) version: 2.2.7(@element-hq/element-web-module-api@1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)
'@element-hq/element-web-playwright-common-local': '@element-hq/element-web-playwright-common-local':
specifier: workspace:* specifier: workspace:*
version: link:packages/playwright-common version: link:packages/playwright-common
@@ -743,7 +743,7 @@ importers:
dependencies: dependencies:
'@element-hq/element-web-module-api': '@element-hq/element-web-module-api':
specifier: 'catalog:' specifier: 'catalog:'
version: 1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4) version: 1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
'@matrix-org/spec': '@matrix-org/spec':
specifier: ^1.7.0 specifier: ^1.7.0
version: 1.16.0 version: 1.16.0
@@ -2021,8 +2021,8 @@ packages:
'@element-hq/element-call-embedded@0.16.3': '@element-hq/element-call-embedded@0.16.3':
resolution: {integrity: sha512-OViKJonDaDNVBUW9WdV9mk78/Ruh34C7XsEgt3O8D9z+64C39elbIgllHSoH5S12IRlv9RYrrV37FZLo6QWsDQ==} resolution: {integrity: sha512-OViKJonDaDNVBUW9WdV9mk78/Ruh34C7XsEgt3O8D9z+64C39elbIgllHSoH5S12IRlv9RYrrV37FZLo6QWsDQ==}
'@element-hq/element-web-module-api@1.9.0': '@element-hq/element-web-module-api@1.9.1':
resolution: {integrity: sha512-Ao/V9w+wysZK4bh61LlKlznF10n2ZbD6KcUI46/zUMttXbmJn3ahvbzhEpwYcD+Cjy3ag5ycxLIIGkKV/fncXg==} resolution: {integrity: sha512-eCHHBkaDWc7Ai10b2VmOAkWIQAsur+YZ2kpFrPFVG41wMXn0PbFL+n6wvpbN+mU5Mg7uVIqXhQn4jflHESBUrA==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
peerDependencies: peerDependencies:
'@matrix-org/react-sdk-module-api': '*' '@matrix-org/react-sdk-module-api': '*'
@@ -12085,7 +12085,7 @@ snapshots:
'@element-hq/element-call-embedded@0.16.3': {} '@element-hq/element-call-embedded@0.16.3': {}
'@element-hq/element-web-module-api@1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)': '@element-hq/element-web-module-api@1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)':
dependencies: dependencies:
'@types/react': 19.2.10 '@types/react': 19.2.10
'@types/react-dom': 19.2.3(@types/react@19.2.10) '@types/react-dom': 19.2.3(@types/react@19.2.10)
@@ -12094,10 +12094,10 @@ snapshots:
'@matrix-org/react-sdk-module-api': 2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4) '@matrix-org/react-sdk-module-api': 2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4)
matrix-web-i18n: 3.6.0 matrix-web-i18n: 3.6.0
'@element-hq/element-web-playwright-common@2.2.7(@element-hq/element-web-module-api@1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)': '@element-hq/element-web-playwright-common@2.2.7(@element-hq/element-web-module-api@1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)':
dependencies: dependencies:
'@axe-core/playwright': 4.11.1(playwright-core@1.58.2) '@axe-core/playwright': 4.11.1(playwright-core@1.58.2)
'@element-hq/element-web-module-api': 1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4) '@element-hq/element-web-module-api': 1.9.1(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
'@playwright/test': 1.58.2 '@playwright/test': 1.58.2
'@testcontainers/postgresql': 11.11.0 '@testcontainers/postgresql': 11.11.0
glob: 13.0.6 glob: 13.0.6
+1 -1
View File
@@ -16,7 +16,7 @@ catalog:
"@element-hq/element-web-playwright-common": 2.2.7 "@element-hq/element-web-playwright-common": 2.2.7
"@playwright/test": 1.58.2 "@playwright/test": 1.58.2
# Module API # Module API
"@element-hq/element-web-module-api": 1.9.0 "@element-hq/element-web-module-api": 1.9.1
# Compound # Compound
"@vector-im/compound-design-tokens": 6.9.0 "@vector-im/compound-design-tokens": 6.9.0
"@vector-im/compound-web": 8.3.6 "@vector-im/compound-web": 8.3.6
+4 -4
View File
@@ -23,8 +23,8 @@ export const DAY_MS = HOUR_MS * 24;
*/ */
export function getDaysArray(weekday: Intl.DateTimeFormatOptions["weekday"] = "short"): string[] { export function getDaysArray(weekday: Intl.DateTimeFormatOptions["weekday"] = "short"): string[] {
const sunday = 1672574400000; // 2023-01-01 12:00 UTC const sunday = 1672574400000; // 2023-01-01 12:00 UTC
const { format } = new Intl.DateTimeFormat(getUserLanguage(), { weekday, timeZone: "UTC" }); const dateTimeFormat = new Intl.DateTimeFormat(getUserLanguage(), { weekday, timeZone: "UTC" });
return [...Array(7).keys()].map((day) => format(sunday + day * DAY_MS)); return [...Array(7).keys()].map((day) => dateTimeFormat.format(sunday + day * DAY_MS));
} }
/** /**
@@ -32,8 +32,8 @@ export function getDaysArray(weekday: Intl.DateTimeFormatOptions["weekday"] = "s
* @param month - format desired "numeric" | "2-digit" | "long" | "short" | "narrow" * @param month - format desired "numeric" | "2-digit" | "long" | "short" | "narrow"
*/ */
export function getMonthsArray(month: Intl.DateTimeFormatOptions["month"] = "short"): string[] { export function getMonthsArray(month: Intl.DateTimeFormatOptions["month"] = "short"): string[] {
const { format } = new Intl.DateTimeFormat(getUserLanguage(), { month, timeZone: "UTC" }); const dateTimeFormat = new Intl.DateTimeFormat(getUserLanguage(), { month, timeZone: "UTC" });
return [...Array(12).keys()].map((m) => format(Date.UTC(2021, m))); return [...Array(12).keys()].map((m) => dateTimeFormat.format(Date.UTC(2021, m)));
} }
// XXX: Ideally we could just specify `hour12: boolean` but it has issues on Chrome in the `en` locale // XXX: Ideally we could just specify `hour12: boolean` but it has issues on Chrome in the `en` locale
+1 -1
View File
@@ -93,7 +93,7 @@ export interface IHandle<C extends ComponentType> {
* *
* @param args - Arguments to return to {@link finished}. * @param args - Arguments to return to {@link finished}.
*/ */
close(...args: OnFinishedParams<C>): void; close(this: void, ...args: OnFinishedParams<C>): void;
} }
interface IOptions<C extends ComponentType> { interface IOptions<C extends ComponentType> {
+8 -2
View File
@@ -171,8 +171,14 @@ interface IProps {
handleLeftRight?: boolean; handleLeftRight?: boolean;
handleInputFields?: boolean; handleInputFields?: boolean;
scrollIntoView?: boolean | ScrollIntoViewOptions; scrollIntoView?: boolean | ScrollIntoViewOptions;
children(renderProps: { onKeyDownHandler(ev: React.KeyboardEvent): void; onDragEndHandler(): void }): ReactNode; children(
onKeyDown?(ev: React.KeyboardEvent, state: IState, dispatch: Dispatch<IAction>): void; this: void,
renderProps: {
onKeyDownHandler(this: void, ev: React.KeyboardEvent): void;
onDragEndHandler(this: void): void;
},
): ReactNode;
onKeyDown?(this: void, ev: React.KeyboardEvent, state: IState, dispatch: Dispatch<IAction>): void;
} }
export const findSiblingElement = ( export const findSiblingElement = (
@@ -16,8 +16,8 @@ import { KeyBindingAction } from "../KeyboardShortcuts";
import { getKeyBindingsManager } from "../../KeyBindingsManager"; import { getKeyBindingsManager } from "../../KeyBindingsManager";
interface IProps extends React.ComponentProps<typeof StyledCheckbox> { interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
onChange(): void; // we handle keyup/down ourselves so lose the ChangeEvent onChange(this: void): void; // we handle keyup/down ourselves so lose the ChangeEvent
onClose(): void; // gets called after onChange on KeyBindingAction.ActivateSelectedButton onClose(this: void): void; // gets called after onChange on KeyBindingAction.ActivateSelectedButton
} }
// Semantic component for representing a styled role=menuitemcheckbox // Semantic component for representing a styled role=menuitemcheckbox
@@ -17,8 +17,8 @@ import { getKeyBindingsManager } from "../../KeyBindingsManager";
interface IProps extends React.ComponentProps<typeof StyledRadioButton> { interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
label?: string; label?: string;
onChange(): void; // we handle keyup/down ourselves so lose the ChangeEvent onChange(this: void): void; // we handle keyup/down ourselves so lose the ChangeEvent
onClose(): void; // gets called after onChange on KeyBindingAction.Enter onClose(this: void): void; // gets called after onChange on KeyBindingAction.Enter
} }
// Semantic component for representing a styled role=menuitemradio // Semantic component for representing a styled role=menuitemradio
@@ -14,11 +14,14 @@ import { type FocusHandler } from "./types";
interface IProps { interface IProps {
inputRef?: RefObject<HTMLElement | null>; inputRef?: RefObject<HTMLElement | null>;
children(renderProps: { children(
onFocus: FocusHandler; this: void,
isActive: boolean; renderProps: {
ref: RefCallback<HTMLElement>; onFocus: FocusHandler;
}): ReactElement<any, any>; isActive: boolean;
ref: RefCallback<HTMLElement>;
},
): ReactElement<any, any>;
} }
// Wrapper to allow use of useRovingTabIndex outside of React Functional Components. // Wrapper to allow use of useRovingTabIndex outside of React Functional Components.
@@ -116,7 +116,7 @@ const linkFactory =
); );
export const UnsupportedBrowserView: React.FC<{ export const UnsupportedBrowserView: React.FC<{
onAccept?(): void; onAccept?(this: void): void;
}> = ({ onAccept }) => { }> = ({ onAccept }) => {
const config = SdkConfig.get(); const config = SdkConfig.get();
const brand = config.brand ?? "Element"; const brand = config.brand ?? "Element";
@@ -26,7 +26,7 @@ interface NewRecoveryMethodDialogProps {
/** /**
* Callback when the dialog is dismissed. * Callback when the dialog is dismissed.
*/ */
onFinished(): void; onFinished(this: void): void;
} }
// Export as default instead of a named export so that it can be dynamically imported with React lazy // Export as default instead of a named export so that it can be dynamically imported with React lazy
+2 -2
View File
@@ -92,9 +92,9 @@ export interface IProps extends MenuProps {
closeOnInteraction?: boolean; closeOnInteraction?: boolean;
// Function to be called on menu close // Function to be called on menu close
onFinished(): void; onFinished(this: void): void;
// on resize callback // on resize callback
windowResize?(): void; windowResize?(this: void): void;
} }
interface IState { interface IState {
+1 -1
View File
@@ -16,7 +16,7 @@ import { useRoomState } from "../../hooks/useRoomState.ts";
interface IProps { interface IProps {
room: Room; room: Room;
parent: HTMLElement | null; parent: HTMLElement | null;
onFileDrop(dataTransfer: DataTransfer): void; onFileDrop(this: void, dataTransfer: DataTransfer): void;
} }
interface IState { interface IState {
+1 -1
View File
@@ -87,7 +87,7 @@ interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
// Called with the credentials of a registered user (if they were a ROU that // Called with the credentials of a registered user (if they were a ROU that
// transitioned to PWLU) // transitioned to PWLU)
onRegistered: (credentials: IMatrixClientCreds) => Promise<MatrixClient>; onRegistered: (this: void, credentials: IMatrixClientCreds) => Promise<MatrixClient>;
hideToSRUsers: boolean; hideToSRUsers: boolean;
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
page_type?: string; page_type?: string;
+3 -3
View File
@@ -2023,7 +2023,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.setPageSubtitle(); this.setPageSubtitle();
} }
private onLogoutClick(event: ButtonEvent): void { private onLogoutClick(this: void, event: ButtonEvent): void {
dis.dispatch({ dis.dispatch({
action: "logout", action: "logout",
}); });
@@ -2047,7 +2047,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.stores.resizeNotifier.notifyWindowResized(); this.stores.resizeNotifier.notifyWindowResized();
}; };
private dispatchTimelineResize(): void { private dispatchTimelineResize(this: void): void {
dis.dispatch({ action: "timeline_resize" }); dis.dispatch({ action: "timeline_resize" });
} }
@@ -2068,7 +2068,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}; };
// returns a promise which resolves to the new MatrixClient // returns a promise which resolves to the new MatrixClient
private onRegistered(credentials: IMatrixClientCreds): Promise<MatrixClient> { private onRegistered(this: void, credentials: IMatrixClientCreds): Promise<MatrixClient> {
return Lifecycle.setLoggedIn(credentials); return Lifecycle.setLoggedIn(credentials);
} }
+1 -1
View File
@@ -22,7 +22,7 @@ interface IProps {
} }
export default class RoomSearch extends React.PureComponent<IProps> { export default class RoomSearch extends React.PureComponent<IProps> {
private openSpotlight(): void { private openSpotlight(this: void): void {
defaultDispatcher.fire(Action.OpenSpotlight); defaultDispatcher.fire(Action.OpenSpotlight);
} }
+1 -1
View File
@@ -42,7 +42,7 @@ interface Props {
promise: Promise<ISearchResults>; promise: Promise<ISearchResults>;
abortController?: AbortController; abortController?: AbortController;
className: string; className: string;
onUpdate(inProgress: boolean, results: ISearchResults | null, error: Error | null): void; onUpdate(this: void, inProgress: boolean, results: ISearchResults | null, error: Error | null): void;
ref?: Ref<ScrollPanel>; ref?: Ref<ScrollPanel>;
} }
+8 -8
View File
@@ -78,7 +78,7 @@ interface IProps {
space: Room; space: Room;
initialText?: string; initialText?: string;
additionalButtons?: ReactNode; additionalButtons?: ReactNode;
showRoom(cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, roomType?: RoomType): void; showRoom(this: void, cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, roomType?: RoomType): void;
} }
interface ITileProps { interface ITileProps {
@@ -88,9 +88,9 @@ interface ITileProps {
numChildRooms?: number; numChildRooms?: number;
hasPermissions?: boolean; hasPermissions?: boolean;
children?: ReactNode; children?: ReactNode;
onViewRoomClick(): void; onViewRoomClick(this: void): void;
onJoinRoomClick(): Promise<unknown>; onJoinRoomClick(this: void): Promise<unknown>;
onToggleClick?(): void; onToggleClick?(this: void): void;
} }
const Tile: React.FC<ITileProps> = ({ const Tile: React.FC<ITileProps> = ({
@@ -468,9 +468,9 @@ interface IHierarchyLevelProps {
hierarchy: RoomHierarchy; hierarchy: RoomHierarchy;
parents: Set<string>; parents: Set<string>;
selectedMap?: Map<string, Set<string>>; selectedMap?: Map<string, Set<string>>;
onViewRoomClick(roomId: string, roomType?: RoomType): void; onViewRoomClick(this: void, roomId: string, roomType?: RoomType): void;
onJoinRoomClick(roomId: string, parents: Set<string>): Promise<unknown>; onJoinRoomClick(this: void, roomId: string, parents: Set<string>): Promise<unknown>;
onToggleClick?(parentId: string, childId: string): void; onToggleClick?(this: void, parentId: string, childId: string): void;
} }
export const toLocalRoom = (cli: MatrixClient, room: HierarchyRoom, hierarchy: RoomHierarchy): HierarchyRoom => { export const toLocalRoom = (cli: MatrixClient, room: HierarchyRoom, hierarchy: RoomHierarchy): HierarchyRoom => {
@@ -600,7 +600,7 @@ export const useRoomHierarchy = (
rooms?: HierarchyRoom[]; rooms?: HierarchyRoom[];
hierarchy?: RoomHierarchy; hierarchy?: RoomHierarchy;
error?: Error; error?: Error;
loadMore(pageSize?: number): Promise<void>; loadMore(this: void, pageSize?: number): Promise<void>;
} => { } => {
const [rooms, setRooms] = useState<HierarchyRoom[]>([]); const [rooms, setRooms] = useState<HierarchyRoom[]>([]);
const [hierarchy, setHierarchy] = useState<RoomHierarchy>(); const [hierarchy, setHierarchy] = useState<RoomHierarchy>();
@@ -13,7 +13,7 @@ const SpacePillButton: React.FC<{
title: string; title: string;
icon: JSX.Element; icon: JSX.Element;
description: string; description: string;
onClick(): void; onClick(this: void): void;
}> = ({ title, icon, description, onClick }) => { }> = ({ title, icon, description, onClick }) => {
return ( return (
<AccessibleButton className="mx_SpacePillButton" onClick={onClick}> <AccessibleButton className="mx_SpacePillButton" onClick={onClick}>
+5 -5
View File
@@ -304,7 +304,7 @@ const SpaceSetupFirstRooms: React.FC<{
space: Room; space: Room;
title: string; title: string;
description: JSX.Element; description: JSX.Element;
onFinished(firstRoomId?: string): void; onFinished(this: void, firstRoomId?: string): void;
}> = ({ space, title, description, onFinished }) => { }> = ({ space, title, description, onFinished }) => {
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [error, setError] = useState(""); const [error, setError] = useState("");
@@ -399,7 +399,7 @@ const SpaceSetupFirstRooms: React.FC<{
const SpaceAddExistingRooms: React.FC<{ const SpaceAddExistingRooms: React.FC<{
space: Room; space: Room;
onFinished(): void; onFinished(this: void): void;
}> = ({ space, onFinished }) => { }> = ({ space, onFinished }) => {
return ( return (
<div> <div>
@@ -423,7 +423,7 @@ const SpaceAddExistingRooms: React.FC<{
}; };
interface ISpaceSetupPublicShareProps extends Pick<IProps & IState, "justCreatedOpts" | "space" | "firstRoomId"> { interface ISpaceSetupPublicShareProps extends Pick<IProps & IState, "justCreatedOpts" | "space" | "firstRoomId"> {
onFinished(): void; onFinished(this: void): void;
} }
const SpaceSetupPublicShare: React.FC<ISpaceSetupPublicShareProps> = ({ const SpaceSetupPublicShare: React.FC<ISpaceSetupPublicShareProps> = ({
@@ -455,7 +455,7 @@ const SpaceSetupPublicShare: React.FC<ISpaceSetupPublicShareProps> = ({
const SpaceSetupPrivateScope: React.FC<{ const SpaceSetupPrivateScope: React.FC<{
space: Room; space: Room;
justCreatedOpts?: IOpts; justCreatedOpts?: IOpts;
onFinished(createRooms: boolean): void; onFinished(this: void, createRooms: boolean): void;
}> = ({ space, justCreatedOpts, onFinished }) => { }> = ({ space, justCreatedOpts, onFinished }) => {
return ( return (
<div className="mx_SpaceRoomView_privateScope"> <div className="mx_SpaceRoomView_privateScope">
@@ -498,7 +498,7 @@ const validateEmailRules = withValidation({
const SpaceSetupPrivateInvite: React.FC<{ const SpaceSetupPrivateInvite: React.FC<{
space: Room; space: Room;
onFinished(): void; onFinished(this: void): void;
}> = ({ space, onFinished }) => { }> = ({ space, onFinished }) => {
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [error, setError] = useState(""); const [error, setError] = useState("");
@@ -27,7 +27,7 @@ interface Props {
* *
* @param event - The click event * @param event - The click event
*/ */
onLogoutClick: (event: ButtonEvent) => void; onLogoutClick: (this: void, event: ButtonEvent) => void;
/** /**
* Error that caused `/sync` to fail. If set, an error message will be shown on the splash screen. * Error that caused `/sync` to fail. If set, an error message will be shown on the splash screen.
+1 -1
View File
@@ -33,7 +33,7 @@ interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idNam
roomId?: string; roomId?: string;
}; };
viewAvatarOnClick?: boolean; viewAvatarOnClick?: boolean;
onClick?(): void; onClick?(this: void): void;
} }
const RoomAvatar: React.FC<IProps> = ({ room, viewAvatarOnClick, onClick, oobData, size = "36px", ...otherProps }) => { const RoomAvatar: React.FC<IProps> = ({ room, viewAvatarOnClick, onClick, oobData, size = "36px", ...otherProps }) => {
@@ -33,7 +33,7 @@ export interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
// open the map centered on this beacon's location // open the map centered on this beacon's location
initialFocusedBeacon?: Beacon; initialFocusedBeacon?: Beacon;
onFinished(): void; onFinished(this: void): void;
} }
// track the 'focused time' as ts // track the 'focused time' as ts
@@ -36,9 +36,9 @@ interface IProps extends Omit<ComponentProps<typeof IconizedContextMenu>, "child
userWidget?: boolean; userWidget?: boolean;
showUnpin?: boolean; showUnpin?: boolean;
// override delete handler // override delete handler
onDeleteClick?(): void; onDeleteClick?(this: void): void;
// override edit handler // override edit handler
onEditClick?(): void; onEditClick?(this: void): void;
} }
const showStreamAudioStreamButton = (app: IWidget): boolean => { const showStreamAudioStreamButton = (app: IWidget): boolean => {
@@ -17,8 +17,8 @@ import { AddExistingToSpace, defaultSpacesRenderer, SubspaceSelector } from "./A
interface IProps { interface IProps {
space: Room; space: Room;
onCreateSubspaceClick(): void; onCreateSubspaceClick(this: void): void;
onFinished(added?: boolean): void; onFinished(this: void, added?: boolean): void;
} }
const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceClick, onFinished }) => { const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceClick, onFinished }) => {
@@ -43,15 +43,15 @@ const GROUP_MARGIN = 24;
interface IProps { interface IProps {
space: Room; space: Room;
onCreateRoomClick(ev: ButtonEvent): void; onCreateRoomClick(this: void, ev: ButtonEvent): void;
onAddSubspaceClick(): void; onAddSubspaceClick(this: void): void;
onFinished(added?: boolean): void; onFinished(this: void, added?: boolean): void;
} }
export const Entry: React.FC<{ export const Entry: React.FC<{
room: Room; room: Room;
checked: boolean; checked: boolean;
onChange?(value: boolean): void; onChange?(this: void, value: boolean): void;
}> = ({ room, checked, onChange }) => { }> = ({ room, checked, onChange }) => {
const id = useId(); const id = useId();
return ( return (
@@ -86,7 +86,7 @@ interface IAddExistingToSpaceProps {
footerPrompt?: ReactNode; footerPrompt?: ReactNode;
filterPlaceholder: string; filterPlaceholder: string;
emptySelectionButton?: ReactNode; emptySelectionButton?: ReactNode;
onFinished(added: boolean): void; onFinished(this: void, added: boolean): void;
roomsRenderer?: Renderer; roomsRenderer?: Renderer;
spacesRenderer?: Renderer; spacesRenderer?: Renderer;
dmsRenderer?: Renderer; dmsRenderer?: Renderer;
@@ -391,7 +391,7 @@ interface ISubspaceSelectorProps {
title: string; title: string;
space: Room; space: Room;
value: Room; value: Room;
onChange(space: Room): void; onChange(this: void, space: Room): void;
} }
export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, space, value, onChange }) => { export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, space, value, onChange }) => {
@@ -23,7 +23,7 @@ export enum ButtonClicked {
} }
interface IProps { interface IProps {
onFinished(buttonClicked?: ButtonClicked): void; onFinished(this: void, buttonClicked?: ButtonClicked): void;
analyticsOwner: string; analyticsOwner: string;
privacyPolicyUrl?: string; privacyPolicyUrl?: string;
primaryButton?: string; primaryButton?: string;
@@ -21,7 +21,7 @@ import { type SettingKey } from "../../../settings/Settings.tsx";
interface IProps { interface IProps {
featureId: SettingKey; featureId: SettingKey;
onFinished(sendFeedback?: boolean): void; onFinished(this: void, sendFeedback?: boolean): void;
} }
const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => { const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
@@ -29,7 +29,7 @@ interface Props {
matrixClient: MatrixClient; matrixClient: MatrixClient;
room: Room; room: Room;
member: RoomMember; member: RoomMember;
onFinished(redact?: boolean): void; onFinished(this: void, redact?: boolean): void;
} }
const BulkRedactDialog: React.FC<Props> = (props) => { const BulkRedactDialog: React.FC<Props> = (props) => {
@@ -88,7 +88,7 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
} }
} }
private elementsForCommit(commit: Commit): JSX.Element { private elementsForCommit(this: void, commit: Commit): JSX.Element {
return ( return (
<li key={commit.sha} className="mx_ChangelogDialog_li"> <li key={commit.sha} className="mx_ChangelogDialog_li">
<a href={commit.html_url} target="_blank" rel="noreferrer noopener"> <a href={commit.html_url} target="_blank" rel="noreferrer noopener">
@@ -21,8 +21,8 @@ interface IProps extends Omit<BaseProps, "matrixClient" | "children" | "onFinish
specificLabel: string; specificLabel: string;
noneLabel?: string; noneLabel?: string;
warningMessage?: string; warningMessage?: string;
onFinished(success?: boolean, reason?: string, rooms?: Room[]): void; onFinished(this: void, success?: boolean, reason?: string, rooms?: Room[]): void;
spaceChildFilter?(child: Room): boolean; spaceChildFilter?(this: void, child: Room): boolean;
} }
const ConfirmSpaceUserActionDialog: React.FC<IProps> = ({ const ConfirmSpaceUserActionDialog: React.FC<IProps> = ({
@@ -23,8 +23,8 @@ import JoinRuleDropdown from "../elements/JoinRuleDropdown";
interface IProps { interface IProps {
space: Room; space: Room;
onAddExistingSpaceClick(): void; onAddExistingSpaceClick(this: void): void;
onFinished(added?: boolean): void; onFinished(this: void, added?: boolean): void;
} }
const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick, onFinished }) => { const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick, onFinished }) => {
@@ -61,7 +61,7 @@ const Tools: Record<Category, [label: TranslationKey, tool: Tool][]> = {
interface IProps { interface IProps {
roomId: string; roomId: string;
threadRootId?: string | null; threadRootId?: string | null;
onFinished(finished?: boolean): void; onFinished(this: void, finished?: boolean): void;
} }
type ToolInfo = [label: TranslationKey, tool: Tool]; type ToolInfo = [label: TranslationKey, tool: Tool];
@@ -37,7 +37,7 @@ import { validateNumberInRange } from "../../../utils/validate";
interface IProps { interface IProps {
room: Room; room: Room;
onFinished(doExport?: boolean): void; onFinished(this: void, doExport?: boolean): void;
} }
interface ExportConfig { interface ExportConfig {
@@ -73,7 +73,7 @@ interface IProps {
// We need a permalink creator for the source room to pass through to EventTile // We need a permalink creator for the source room to pass through to EventTile
// in case the event is a reply (even though the user can't get at the link) // in case the event is a reply (even though the user can't get at the link)
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
onFinished(): void; onFinished(this: void): void;
} }
interface IEntryProps<K extends keyof TimelineEvents> { interface IEntryProps<K extends keyof TimelineEvents> {
@@ -81,7 +81,7 @@ interface IEntryProps<K extends keyof TimelineEvents> {
type: K; type: K;
content: TimelineEvents[K]; content: TimelineEvents[K];
matrixClient: MatrixClient; matrixClient: MatrixClient;
onFinished(success: boolean): void; onFinished(this: void, success: boolean): void;
} }
enum SendState { enum SendState {
@@ -22,7 +22,7 @@ interface IProps {
rageshakeLabel?: string; rageshakeLabel?: string;
rageshakeData?: Record<string, any>; rageshakeData?: Record<string, any>;
children?: ReactNode; children?: ReactNode;
onFinished(sendFeedback?: boolean): void; onFinished(this: void, sendFeedback?: boolean): void;
} }
const GenericFeatureFeedbackDialog: React.FC<IProps> = ({ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
@@ -16,7 +16,7 @@ import DialogButtons from "../elements/DialogButtons";
import { UserTab } from "./UserTab"; import { UserTab } from "./UserTab";
interface IProps { interface IProps {
onFinished(): void; onFinished(this: void): void;
} }
export const IntegrationsDisabledDialog: React.FC<IProps> = ({ onFinished }) => { export const IntegrationsDisabledDialog: React.FC<IProps> = ({ onFinished }) => {
@@ -1124,7 +1124,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
this.setState({ currentTabId: tabId }); this.setState({ currentTabId: tabId });
}; };
private async onLinkClick(e: React.MouseEvent<HTMLAnchorElement>): Promise<void> { private async onLinkClick(this: void, e: React.MouseEvent<HTMLAnchorElement>): Promise<void> {
e.preventDefault(); e.preventDefault();
selectText(e.currentTarget); selectText(e.currentTarget);
} }
@@ -20,7 +20,7 @@ import { isOnlyAdmin } from "../../../utils/membership";
interface IProps { interface IProps {
space: Room; space: Room;
onFinished(leave: boolean, rooms?: Room[]): void; onFinished(this: void, leave: boolean, rooms?: Room[]): void;
} }
const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => { const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
@@ -25,13 +25,13 @@ import { filterBoolean } from "../../../utils/arrays";
interface IProps { interface IProps {
room: Room; room: Room;
selected?: string[]; selected?: string[];
onFinished(rooms?: string[]): void; onFinished(this: void, rooms?: string[]): void;
} }
const Entry: React.FC<{ const Entry: React.FC<{
room: Room; room: Room;
checked: boolean; checked: boolean;
onChange(value: boolean): void; onChange(this: void, value: boolean): void;
}> = ({ room, checked, onChange }) => { }> = ({ room, checked, onChange }) => {
const localRoom = room instanceof Room; const localRoom = room instanceof Room;
@@ -17,7 +17,7 @@ type PollHistoryDialogProps = {
room: Room; room: Room;
matrixClient: MatrixClient; matrixClient: MatrixClient;
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
onFinished(): void; onFinished(this: void): void;
}; };
export const PollHistoryDialog: React.FC<PollHistoryDialogProps> = ({ export const PollHistoryDialog: React.FC<PollHistoryDialogProps> = ({
@@ -15,8 +15,8 @@ import DialogButtons from "../elements/DialogButtons";
import EmailField from "../auth/EmailField"; import EmailField from "../auth/EmailField";
interface IProps { interface IProps {
onFinished(continued: false, email?: undefined): void; onFinished(this: void, continued: false, email?: undefined): void;
onFinished(continued: true, email: string): void; onFinished(this: void, continued: true, email: string): void;
} }
const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => { const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
@@ -25,7 +25,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface IProps { interface IProps {
roomId: string; roomId: string;
onFinished(leave: boolean): void; onFinished(this: void, leave: boolean): void;
} }
/* /*
+1 -1
View File
@@ -56,7 +56,7 @@ interface BaseProps {
/** /**
* A function that is called when the dialog is dismissed * A function that is called when the dialog is dismissed
*/ */
onFinished(): void; onFinished(this: void): void;
/** /**
* An optional string to use as the dialog title. * An optional string to use as the dialog title.
* If not provided, an appropriate title for the target type will be used. * If not provided, an appropriate title for the target type will be used.
@@ -20,7 +20,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
*/ */
interface IProps { interface IProps {
roomId: string; roomId: string;
onFinished(): void; onFinished(this: void): void;
} }
const SlashCommandHelpDialog: React.FC<IProps> = ({ roomId, onFinished }) => { const SlashCommandHelpDialog: React.FC<IProps> = ({ roomId, onFinished }) => {
@@ -26,7 +26,7 @@ import { SettingsSubsection, SettingsSubsectionText } from "../settings/shared/S
interface IProps { interface IProps {
space: Room; space: Room;
onFinished(): void; onFinished(this: void): void;
} }
const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space }) => { const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space }) => {
@@ -39,7 +39,7 @@ export enum SpaceSettingsTab {
interface IProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
space: Room; space: Room;
onFinished(): void; onFinished(this: void): void;
} }
const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => { const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => {
@@ -31,7 +31,7 @@ interface IProps {
* If mode is "sas", the user wants to verify the device with SAS. Otherwise, the dialog was dismissed normally. * If mode is "sas", the user wants to verify the device with SAS. Otherwise, the dialog was dismissed normally.
* @param mode The mode of dismissal. * @param mode The mode of dismissal.
*/ */
onFinished(mode?: "sas"): void; onFinished(this: void, mode?: "sas"): void;
} }
const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => { const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => {
@@ -58,7 +58,7 @@ interface IProps {
*/ */
initialEncryptionState?: State; initialEncryptionState?: State;
sdkContext: SdkContextClass; sdkContext: SdkContextClass;
onFinished(): void; onFinished(this: void): void;
} }
function titleForTabID(tabId: UserTab): React.ReactNode { function titleForTabID(tabId: UserTab): React.ReactNode {
@@ -16,8 +16,8 @@ import { type XOR } from "../../../../@types/common";
import { type Tool } from "../DevtoolsDialog"; import { type Tool } from "../DevtoolsDialog";
export interface IDevtoolsProps { export interface IDevtoolsProps {
onBack(): void; onBack(this: void): void;
setTool(label: TranslationKey, tool: Tool): void; setTool(this: void, label: TranslationKey, tool: Tool): void;
} }
interface IMinProps extends Pick<IDevtoolsProps, "onBack"> { interface IMinProps extends Pick<IDevtoolsProps, "onBack"> {
@@ -28,7 +28,7 @@ interface IMinProps extends Pick<IDevtoolsProps, "onBack"> {
interface IProps extends IMinProps { interface IProps extends IMinProps {
actionLabel: TranslationKey; actionLabel: TranslationKey;
onAction(): Promise<string | void>; onAction(this: void): Promise<string | void>;
} }
const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({ const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({
@@ -20,7 +20,7 @@ interface KeyBackupProps {
/** /**
* Callback to invoke when the back button is clicked. * Callback to invoke when the back button is clicked.
*/ */
onBack(): void; onBack(this: void): void;
} }
/** /**
@@ -24,7 +24,7 @@ export const stringify = (object: object): string => {
interface IEventEditorProps extends Pick<IDevtoolsProps, "onBack"> { interface IEventEditorProps extends Pick<IDevtoolsProps, "onBack"> {
fieldDefs: IFieldDef[]; // immutable fieldDefs: IFieldDef[]; // immutable
defaultContent?: string; defaultContent?: string;
onSend(fields: string[], content: IContent): Promise<unknown>; onSend(this: void, fields: string[], content: IContent): Promise<unknown>;
} }
interface IFieldDef { interface IFieldDef {
@@ -19,7 +19,7 @@ const LOAD_TILES_STEP_SIZE = 50;
interface IProps { interface IProps {
children: React.ReactElement[]; children: React.ReactElement[];
query: string; query: string;
onChange(value: string): void; onChange(this: void, value: string): void;
} }
const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => { const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
@@ -40,12 +40,12 @@ export const StateEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack }) =>
interface StateEventButtonProps { interface StateEventButtonProps {
label: string; label: string;
onClick(): void; onClick(this: void): void;
} }
const RoomStateHistory: React.FC<{ const RoomStateHistory: React.FC<{
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onBack(): void; onBack(this: void): void;
}> = ({ mxEvent, onBack }) => { }> = ({ mxEvent, onBack }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const events = useAsyncMemo( const events = useAsyncMemo(
@@ -192,7 +192,7 @@ const EditSetting: React.FC<IEditSettingProps> = ({ setting, onBack }) => {
interface IViewSettingProps extends Pick<IDevtoolsProps, "onBack"> { interface IViewSettingProps extends Pick<IDevtoolsProps, "onBack"> {
setting: SettingKey; setting: SettingKey;
onEdit(): Promise<void>; onEdit(this: void): Promise<void>;
} }
const ViewSetting: React.FC<IViewSettingProps> = ({ setting, onEdit, onBack }) => { const ViewSetting: React.FC<IViewSettingProps> = ({ setting, onEdit, onBack }) => {
@@ -249,8 +249,8 @@ function renderSettingValue(val: any): string {
} }
interface ISettingsListProps extends Pick<IDevtoolsProps, "onBack"> { interface ISettingsListProps extends Pick<IDevtoolsProps, "onBack"> {
onView(setting: string): void; onView(this: void, setting: string): void;
onEdit(setting: string): void; onEdit(this: void, setting: string): void;
} }
const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit }) => { const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit }) => {
@@ -78,7 +78,7 @@ export const UserList: React.FC<Pick<IDevtoolsProps, "onBack">> = ({ onBack }) =
interface UserButtonProps { interface UserButtonProps {
member: RoomMember; member: RoomMember;
onClick(): void; onClick(this: void): void;
} }
/** /**
@@ -216,7 +216,7 @@ const UserView: React.FC<UserProps> = ({ member, onBack }) => {
interface DeviceButtonProps { interface DeviceButtonProps {
crypto: CryptoApi; crypto: CryptoApi;
device: Device; device: Device;
onClick(): void; onClick(this: void): void;
} }
/** /**
@@ -106,7 +106,7 @@ const AVATAR_SIZE = "24px";
interface IProps { interface IProps {
initialText?: string; initialText?: string;
initialFilter?: Filter; initialFilter?: Filter;
onFinished(): void; onFinished(this: void): void;
} }
function nodeIsForRecentlyViewed(node?: HTMLElement): boolean { function nodeIsForRecentlyViewed(node?: HTMLElement): boolean {
@@ -191,7 +191,7 @@ interface IResult extends IBaseResult {
avatar: JSX.Element; avatar: JSX.Element;
name: string; name: string;
description?: string; description?: string;
onClick?(): void; onClick?(this: void): void;
} }
type Result = IRoomResult | IPublicRoomResult | IMemberResult | IResult; type Result = IRoomResult | IPublicRoomResult | IMemberResult | IResult;
+1 -1
View File
@@ -306,7 +306,7 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
return keys[index <= 0 ? keys.length - 1 : (index - 1) % keys.length]; return keys[index <= 0 ? keys.length - 1 : (index - 1) % keys.length];
} }
private scrollIntoView(node: Element | null): void { private scrollIntoView(this: void, node: Element | null): void {
node?.scrollIntoView({ node?.scrollIntoView({
block: "nearest", block: "nearest",
behavior: "auto", behavior: "auto",
@@ -31,7 +31,7 @@ interface IProps {
// An array of EventTiles to render when expanded // An array of EventTiles to render when expanded
"children": ReactNode[] | null; "children": ReactNode[] | null;
// Called when the event list expansion is toggled // Called when the event list expansion is toggled
onToggle?(): void; onToggle?(this: void): void;
// The layout currently used // The layout currently used
"layout"?: Layout; "layout"?: Layout;
"data-testid"?: string; "data-testid"?: string;
@@ -26,7 +26,7 @@ interface IProps {
labelKnock?: string; labelKnock?: string;
labelPublic?: string; labelPublic?: string;
labelRestricted?: string; // if omitted then this option will be hidden, e.g if unsupported labelRestricted?: string; // if omitted then this option will be hidden, e.g if unsupported
onChange(value: JoinRule): void; onChange(this: void, value: JoinRule): void;
} }
const JoinRuleDropdown: React.FC<IProps> = ({ const JoinRuleDropdown: React.FC<IProps> = ({
@@ -21,7 +21,7 @@ interface IProps {
// Whether or not to disable the checkbox // Whether or not to disable the checkbox
disabled?: boolean; disabled?: boolean;
// The function to call when the value changes // The function to call when the value changes
onChange(checked: boolean): void; onChange(this: void, checked: boolean): void;
// Optional additional CSS class to apply to the label // Optional additional CSS class to apply to the label
className?: string; className?: string;
// The id for the checkbox // The id for the checkbox
@@ -24,9 +24,9 @@ interface IProps {
hasAvatar: boolean; hasAvatar: boolean;
noAvatarLabel?: string; noAvatarLabel?: string;
hasAvatarLabel?: string; hasAvatarLabel?: string;
setAvatarUrl(url: string): Promise<unknown>; setAvatarUrl(this: void, url: string): Promise<unknown>;
isUserAvatar?: boolean; isUserAvatar?: boolean;
onClick?(ev: MouseEvent<HTMLInputElement>): void; onClick?(this: void, ev: MouseEvent<HTMLInputElement>): void;
children?: ReactNode; children?: ReactNode;
} }
+1 -1
View File
@@ -13,7 +13,7 @@ import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
interface IProps { interface IProps {
room?: Room; room?: Room;
children?(name: string): JSX.Element; children?(this: void, name: string): JSX.Element;
} }
/** /**
@@ -23,7 +23,7 @@ interface IProps {
dialogTitle?: string; dialogTitle?: string;
serverConfig: ValidatedServerConfig; serverConfig: ValidatedServerConfig;
disabled?: boolean; disabled?: boolean;
onServerConfigChange?(config: ValidatedServerConfig): void; onServerConfigChange?(this: void, config: ValidatedServerConfig): void;
} }
const showPickerDialog = ( const showPickerDialog = (
@@ -21,7 +21,7 @@ interface Props {
label?: string; label?: string;
isExplicit?: boolean; isExplicit?: boolean;
hideIfCannotSet?: boolean; hideIfCannotSet?: boolean;
onChange?(option: string): void; onChange?(this: void, option: string): void;
} }
const SettingsDropdown = ({ const SettingsDropdown = ({
@@ -19,7 +19,7 @@ interface Props {
roomId?: string; // for per-room settings roomId?: string; // for per-room settings
label?: string; label?: string;
isExplicit?: boolean; isExplicit?: boolean;
onChange?(value: string): void; onChange?(this: void, value: string): void;
} }
const SettingsField = ({ settingKey, level, roomId, isExplicit, label, onChange: _onSave }: Props): JSX.Element => { const SettingsField = ({ settingKey, level, roomId, isExplicit, label, onChange: _onSave }: Props): JSX.Element => {
@@ -81,9 +81,9 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
} }
} }
private onSearchChange(searchQuery: string): void { private onSearchChange = (searchQuery: string): void => {
this.setState({ searchQuery }); this.setState({ searchQuery });
} };
public render(): React.ReactNode { public render(): React.ReactNode {
if (!this.state.languages) { if (!this.state.languages) {
@@ -27,7 +27,7 @@ interface IProps<T extends string> {
value?: T; // if not provided no options will be selected value?: T; // if not provided no options will be selected
outlined?: boolean; outlined?: boolean;
disabled?: boolean; disabled?: boolean;
onChange(newValue: T): void; onChange(this: void, newValue: T): void;
} }
function StyledRadioGroup<T extends string>({ function StyledRadioGroup<T extends string>({
@@ -25,7 +25,7 @@ interface IProps {
tooltip?: string; tooltip?: string;
// Called when the checked state changes. First argument will be the new state. // Called when the checked state changes. First argument will be the new state.
onChange(checked: boolean): void; onChange(this: void, checked: boolean): void;
// id to bind with other elements // id to bind with other elements
id?: string; id?: string;
+3 -1
View File
@@ -33,7 +33,7 @@ interface IArgs<T, D = void> {
rules: IRule<T, D>[]; rules: IRule<T, D>[];
description?(this: T, derivedData: D, results: IResult[]): ReactNode; description?(this: T, derivedData: D, results: IResult[]): ReactNode;
hideDescriptionIfValid?: boolean; hideDescriptionIfValid?: boolean;
deriveData?(data: Data): Promise<D>; deriveData?(this: T, data: Data): Promise<D>;
memoize?: boolean; memoize?: boolean;
} }
@@ -78,8 +78,10 @@ export interface IValidationResult {
* the overall validity and a feedback UI that can be rendered for more detail. * the overall validity and a feedback UI that can be rendered for more detail.
*/ */
export default function withValidation<T = void, D = void>({ export default function withValidation<T = void, D = void>({
// eslint-disable-next-line @typescript-eslint/unbound-method
description, description,
hideDescriptionIfValid, hideDescriptionIfValid,
// eslint-disable-next-line @typescript-eslint/unbound-method
deriveData, deriveData,
rules, rules,
memoize, memoize,
+1 -1
View File
@@ -32,7 +32,7 @@ const useMapWithStyle = ({
}: { }: {
id: string; id: string;
centerGeoUri?: string; centerGeoUri?: string;
onError?(error: Error): void; onError?(this: void, error: Error): void;
interactive?: boolean; interactive?: boolean;
bounds?: Bounds; bounds?: Bounds;
allowGeolocate?: boolean; allowGeolocate?: boolean;
+1 -1
View File
@@ -23,7 +23,7 @@ interface Props {
const ExpandCollapseButton: React.FC<{ const ExpandCollapseButton: React.FC<{
expanded: boolean; expanded: boolean;
onClick(): void; onClick(this: void): void;
}> = ({ expanded, onClick }) => { }> = ({ expanded, onClick }) => {
return ( return (
<span className="mx_EventTile_button" onClick={onClick}> <span className="mx_EventTile_button" onClick={onClick}>
@@ -16,7 +16,7 @@ import { useRoomMemberProfile } from "../../../hooks/room/useRoomMemberProfile";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onClick?(): void; onClick?(this: void): void;
withTooltip?: boolean; withTooltip?: boolean;
} }
@@ -23,7 +23,7 @@ type PollHistoryProps = {
room: Room; room: Room;
matrixClient: MatrixClient; matrixClient: MatrixClient;
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
onFinished(): void; onFinished(this: void): void;
}; };
const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs(); const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs();
@@ -28,9 +28,9 @@ interface IProps {
ariaLabelledBy?: string; ariaLabelledBy?: string;
withoutScrollContainer?: boolean; withoutScrollContainer?: boolean;
closeLabel?: string; closeLabel?: string;
onClose?(ev: MouseEvent<HTMLButtonElement>): void; onClose?(this: void, ev: MouseEvent<HTMLButtonElement>): void;
onBack?(ev: MouseEvent<HTMLButtonElement>): void; onBack?(this: void, ev: MouseEvent<HTMLButtonElement>): void;
onKeyDown?(ev: KeyboardEvent): void; onKeyDown?(this: void, ev: KeyboardEvent): void;
cardState?: any; cardState?: any;
ref?: Ref<HTMLDivElement>; ref?: Ref<HTMLDivElement>;
// Ref for the 'close' button the card // Ref for the 'close' button the card
@@ -35,7 +35,7 @@ import { WidgetContextMenu } from "../../../viewmodels/right-panel/WidgetContext
interface Props { interface Props {
room: Room; room: Room;
onClose(): void; onClose(this: void): void;
} }
interface IAppRowProps { interface IAppRowProps {
@@ -44,7 +44,7 @@ interface PinnedMessagesCardProps {
/** /**
* Callback for when the card is closed. * Callback for when the card is closed.
*/ */
onClose(): void; onClose(this: void): void;
} }
export function PinnedMessagesCard({ room, onClose, permalinkCreator }: PinnedMessagesCardProps): JSX.Element { export function PinnedMessagesCard({ room, onClose, permalinkCreator }: PinnedMessagesCardProps): JSX.Element {
@@ -192,7 +192,7 @@ interface IProps {
user: Member; user: Member;
room?: Room; room?: Room;
phase: RightPanelPhases.MemberInfo | RightPanelPhases.EncryptionPanel; phase: RightPanelPhases.MemberInfo | RightPanelPhases.EncryptionPanel;
onClose(): void; onClose(this: void): void;
verificationRequest?: VerificationRequest; verificationRequest?: VerificationRequest;
verificationRequestPromise?: Promise<VerificationRequest>; verificationRequestPromise?: Promise<VerificationRequest>;
} }
@@ -23,7 +23,7 @@ import { WidgetContextMenu } from "../../../viewmodels/right-panel/WidgetContext
interface IProps { interface IProps {
room: Room; room: Room;
widgetId: string; widgetId: string;
onClose(): void; onClose(this: void): void;
} }
const WidgetCard: React.FC<IProps> = ({ room, widgetId, onClose }) => { const WidgetCard: React.FC<IProps> = ({ room, widgetId, onClose }) => {
@@ -33,8 +33,8 @@ const Container: React.FC<{
interface IBaseProps { interface IBaseProps {
member: RoomMember; member: RoomMember;
isUpdating: boolean; isUpdating: boolean;
startUpdating(): void; startUpdating(this: void): void;
stopUpdating(): void; stopUpdating(this: void): void;
} }
export const RoomKickButton = ({ export const RoomKickButton = ({

Some files were not shown because too many files have changed in this diff Show More