mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 19:56:45 +02:00
Extend the Module API in prep of restricted-guests module
This commit is contained in:
parent
e481865aa6
commit
9763807c42
@ -4,11 +4,26 @@
|
||||
|
||||
```ts
|
||||
|
||||
import { ComponentType } from 'react';
|
||||
import { JSX } from 'react';
|
||||
import { ModuleApi } from '@matrix-org/react-sdk-module-api';
|
||||
import { Root } from 'react-dom/client';
|
||||
import { RuntimeModule } from '@matrix-org/react-sdk-module-api';
|
||||
|
||||
// @public
|
||||
export interface AccountAuthApiExtension {
|
||||
overwriteAccountAuth(accountInfo: AccountAuthInfo): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface AccountAuthInfo {
|
||||
accessToken: string;
|
||||
deviceId: string;
|
||||
homeserverUrl: string;
|
||||
refreshToken?: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
// @alpha @deprecated (undocumented)
|
||||
export interface AliasCustomisations {
|
||||
// (undocumented)
|
||||
@ -19,12 +34,13 @@ export interface AliasCustomisations {
|
||||
// Warning: (ae-incompatible-release-tags) The symbol "Api" is marked as @public, but its signature references "LegacyCustomisationsApiExtension" which is marked as @alpha
|
||||
//
|
||||
// @public
|
||||
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension {
|
||||
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension, DialogApiExtension, AccountAuthApiExtension, ProfileApiExtension {
|
||||
readonly config: ConfigApi;
|
||||
createRoot(element: Element): Root;
|
||||
// @alpha
|
||||
readonly customComponents: CustomComponentsApi;
|
||||
readonly i18n: I18nApi;
|
||||
readonly navigation: NavigationApi;
|
||||
readonly rootNode: HTMLElement;
|
||||
}
|
||||
|
||||
@ -63,6 +79,7 @@ export interface ConfigApi {
|
||||
// @alpha
|
||||
export interface CustomComponentsApi {
|
||||
registerMessageRenderer(eventTypeOrFilter: string | ((mxEvent: MatrixEvent) => boolean), renderer: CustomMessageRenderFunction, hints?: CustomMessageRenderHints): void;
|
||||
registerRoomPreviewBar(renderer: CustomRoomPreviewBarRenderFunction): void;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
@ -73,13 +90,49 @@ export type CustomMessageComponentProps = {
|
||||
// @alpha
|
||||
export type CustomMessageRenderFunction = (
|
||||
props: CustomMessageComponentProps,
|
||||
originalComponent?: (props?: OriginalComponentProps) => React.JSX.Element) => JSX.Element;
|
||||
originalComponent?: (props?: OriginalMessageComponentProps) => React.JSX.Element) => JSX.Element;
|
||||
|
||||
// @alpha
|
||||
export type CustomMessageRenderHints = {
|
||||
allowEditingEvent?: boolean;
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export type CustomRoomPreviewBarComponentProps = {
|
||||
roomId?: string;
|
||||
roomAlias?: string;
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export type CustomRoomPreviewBarRenderFunction = (
|
||||
props: CustomRoomPreviewBarComponentProps,
|
||||
originalComponent: (props: CustomRoomPreviewBarComponentProps) => JSX.Element) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export interface DialogApiExtension {
|
||||
openDialog<M, P>(initialOptions: DialogOptions, dialog: ComponentType<P & DialogProps<M>>, props?: P): DialogHandle<M>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type DialogHandle<M> = {
|
||||
finished: Promise<{
|
||||
ok: boolean;
|
||||
model: M;
|
||||
}>;
|
||||
close(): void;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface DialogOptions {
|
||||
title: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type DialogProps<M> = {
|
||||
onSubmit(model: M): void;
|
||||
cancel(): void;
|
||||
};
|
||||
|
||||
// @alpha @deprecated (undocumented)
|
||||
export interface DirectoryCustomisations {
|
||||
// (undocumented)
|
||||
@ -216,11 +269,28 @@ export class ModuleLoader {
|
||||
start(): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface NavigationApi {
|
||||
toMatrixToLink(link: string, join?: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export type OriginalComponentProps = {
|
||||
export type OriginalMessageComponentProps = {
|
||||
showUrlPreview?: boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface Profile {
|
||||
displayName?: string;
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface ProfileApiExtension {
|
||||
// Warning: (ae-forgotten-export) The symbol "Watchable" needs to be exported by the entry point index.d.ts
|
||||
readonly profile: Watchable<Profile>;
|
||||
}
|
||||
|
||||
// @alpha @deprecated (undocumented)
|
||||
export interface RoomListCustomisations<Room> {
|
||||
isRoomVisible?(room: Room): boolean;
|
||||
|
||||
45
packages/element-web-module-api/src/api/auth.ts
Normal file
45
packages/element-web-module-api/src/api/auth.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for account authentication information, used for overwriting the current account's authentication state.
|
||||
* @public
|
||||
*/
|
||||
export interface AccountAuthInfo {
|
||||
/**
|
||||
* The user ID.
|
||||
*/
|
||||
userId: string;
|
||||
/**
|
||||
* The device ID.
|
||||
*/
|
||||
deviceId: string;
|
||||
/**
|
||||
* The access token belonging to this device ID and user ID.
|
||||
*/
|
||||
accessToken: string;
|
||||
/**
|
||||
* The refresh token belonging to this device ID and user ID.
|
||||
*/
|
||||
refreshToken?: string;
|
||||
/**
|
||||
* The homeserver URL where the credentials are valid.
|
||||
*/
|
||||
homeserverUrl: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods to manage authentication in the application.
|
||||
* @public
|
||||
*/
|
||||
export interface AccountAuthApiExtension {
|
||||
/**
|
||||
* Overwrite the current account's authentication state with the provided account information.
|
||||
* @param accountInfo - The account authentication information to overwrite the current state with.
|
||||
*/
|
||||
overwriteAccountAuth(accountInfo: AccountAuthInfo): Promise<void>;
|
||||
}
|
||||
@ -24,7 +24,7 @@ export type CustomMessageComponentProps = {
|
||||
* Properties to alter the render function of the original component.
|
||||
* @alpha Subject to change.
|
||||
*/
|
||||
export type OriginalComponentProps = {
|
||||
export type OriginalMessageComponentProps = {
|
||||
/**
|
||||
* Should previews be shown for this event.
|
||||
* This may be overriden by user preferences.
|
||||
@ -58,7 +58,31 @@ export type CustomMessageRenderFunction = (
|
||||
/**
|
||||
* Render function for the original component. This may be omitted if the message would not normally be rendered.
|
||||
*/
|
||||
originalComponent?: (props?: OriginalComponentProps) => React.JSX.Element,
|
||||
originalComponent?: (props?: OriginalMessageComponentProps) => React.JSX.Element,
|
||||
) => JSX.Element;
|
||||
|
||||
/**
|
||||
* Properties for all message components.
|
||||
* @alpha Subject to change.
|
||||
*/
|
||||
export type CustomRoomPreviewBarComponentProps = {
|
||||
roomId?: string;
|
||||
roomAlias?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function used to render a room preview bar component.
|
||||
* @alpha Unlikely to change
|
||||
*/
|
||||
export type CustomRoomPreviewBarRenderFunction = (
|
||||
/**
|
||||
* Properties for the room preview bar to be rendered.
|
||||
*/
|
||||
props: CustomRoomPreviewBarComponentProps,
|
||||
/**
|
||||
* Render function for the original component.
|
||||
*/
|
||||
originalComponent: (props: CustomRoomPreviewBarComponentProps) => JSX.Element,
|
||||
) => JSX.Element;
|
||||
|
||||
/**
|
||||
@ -95,4 +119,22 @@ export interface CustomComponentsApi {
|
||||
renderer: CustomMessageRenderFunction,
|
||||
hints?: CustomMessageRenderHints,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Register a renderer for the room preview bar.
|
||||
*
|
||||
* The render function should return a rendered component.
|
||||
*
|
||||
* @param renderer - The render function for the room preview bar.
|
||||
* @example
|
||||
* ```
|
||||
* customComponents.registerRoomPreviewBar((props, OriginalComponent) => {
|
||||
* if (props.roomId === "!some_special_room_id:server") {
|
||||
* return <YourCustomRoomPreviewBarComponent {...props} />;
|
||||
* }
|
||||
* return <YourCustomComponent mxEvent={props.mxEvent} />;
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
registerRoomPreviewBar(renderer: CustomRoomPreviewBarRenderFunction): void;
|
||||
}
|
||||
|
||||
68
packages/element-web-module-api/src/api/dialog.ts
Normal file
68
packages/element-web-module-api/src/api/dialog.ts
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { ComponentType } from "react";
|
||||
|
||||
/**
|
||||
* Options for {@link Api#openDialog}.
|
||||
* @public
|
||||
*/
|
||||
export interface DialogOptions {
|
||||
/**
|
||||
* The title of the dialog.
|
||||
*/
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle returned by {@link Api#openDialog}.
|
||||
* @public
|
||||
*/
|
||||
export type DialogHandle<M> = {
|
||||
/**
|
||||
* Promise that resolves when the dialog is finished.
|
||||
*/
|
||||
finished: Promise<{ ok: boolean; model: M }>;
|
||||
/**
|
||||
* Method to close the dialog.
|
||||
*/
|
||||
close(): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Props passed to the dialog body component.
|
||||
* @public
|
||||
*/
|
||||
export type DialogProps<M> = {
|
||||
/**
|
||||
* Callback to submit the dialog.
|
||||
* @param model - The model to submit with the dialog. This is typically the data collected.
|
||||
*/
|
||||
onSubmit(model: M): void;
|
||||
/**
|
||||
* Cancel the dialog programmatically.
|
||||
*/
|
||||
cancel(): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods to manage dialogs in the application.
|
||||
* @public
|
||||
*/
|
||||
export interface DialogApiExtension {
|
||||
/**
|
||||
* Open a dialog with the given options and body component and return a handle to it.
|
||||
* @param initialOptions - The initial options for the dialog, such as title and action label.
|
||||
* @param dialog - The body component to render in the dialog. This component should accept props of type `P`.
|
||||
* @param props - Additional props to pass to the body
|
||||
*/
|
||||
openDialog<M, P>(
|
||||
initialOptions: DialogOptions,
|
||||
dialog: ComponentType<P & DialogProps<M>>,
|
||||
props?: P,
|
||||
): DialogHandle<M>;
|
||||
}
|
||||
@ -11,6 +11,10 @@ import { LegacyCustomisationsApiExtension } from "./legacy-customisations";
|
||||
import { ConfigApi } from "./config";
|
||||
import { I18nApi } from "./i18n";
|
||||
import { CustomComponentsApi } from "./custom-components";
|
||||
import { NavigationApi } from "./navigation.ts";
|
||||
import { DialogApiExtension } from "./dialog.ts";
|
||||
import { AccountAuthApiExtension } from "./auth.ts";
|
||||
import { ProfileApiExtension } from "./profile.ts";
|
||||
|
||||
/**
|
||||
* Module interface for modules to implement.
|
||||
@ -69,7 +73,12 @@ export function isModule(module: unknown): module is ModuleExport {
|
||||
* The API for modules to interact with the application.
|
||||
* @public
|
||||
*/
|
||||
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension {
|
||||
export interface Api
|
||||
extends LegacyModuleApiExtension,
|
||||
LegacyCustomisationsApiExtension,
|
||||
DialogApiExtension,
|
||||
AccountAuthApiExtension,
|
||||
ProfileApiExtension {
|
||||
/**
|
||||
* The API to read config.json values.
|
||||
* Keys should be scoped to the module in reverse domain name notation.
|
||||
@ -93,6 +102,13 @@ export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiEx
|
||||
* @alpha
|
||||
*/
|
||||
readonly customComponents: CustomComponentsApi;
|
||||
|
||||
/**
|
||||
* API to navigate the application.
|
||||
* @public
|
||||
*/
|
||||
readonly navigation: NavigationApi;
|
||||
|
||||
/**
|
||||
* Create a ReactDOM root for rendering React components.
|
||||
* Exposed to allow modules to avoid needing to bundle their own ReactDOM.
|
||||
|
||||
19
packages/element-web-module-api/src/api/navigation.ts
Normal file
19
packages/element-web-module-api/src/api/navigation.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* API methods to navigate the application.
|
||||
* @public
|
||||
*/
|
||||
export interface NavigationApi {
|
||||
/**
|
||||
* Navigate to a permalink, optionally causing a join if the user is not already a member of the room/space.
|
||||
* @param link - The permalink to navigate to, e.g. `https://matrix.to/#/!roomId:example.com`.
|
||||
* @param join - If true, the user will be made to attempt to join the room/space if they are not already a member.
|
||||
*/
|
||||
toMatrixToLink(link: string, join?: boolean): Promise<void>;
|
||||
}
|
||||
34
packages/element-web-module-api/src/api/profile.ts
Normal file
34
packages/element-web-module-api/src/api/profile.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { Watchable } from "./watchable.ts";
|
||||
|
||||
/**
|
||||
* The profile of the user currently logged in.
|
||||
* @public
|
||||
*/
|
||||
export interface Profile {
|
||||
/**
|
||||
* The user ID of the logged-in user, if undefined then no user is logged in.
|
||||
*/
|
||||
userId?: string;
|
||||
/**
|
||||
* The display name of the logged-in user.
|
||||
*/
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* API extensions for modules to access the profile of the logged-in user.
|
||||
* @public
|
||||
*/
|
||||
export interface ProfileApiExtension {
|
||||
/**
|
||||
* The profile of the user currently logged in.
|
||||
*/
|
||||
readonly profile: Watchable<Profile>;
|
||||
}
|
||||
38
packages/element-web-module-api/src/api/watchable.ts
Normal file
38
packages/element-web-module-api/src/api/watchable.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
type WatchFn<T> = (value: T) => void;
|
||||
|
||||
/**
|
||||
* Utility class to wrap a value and allow listeners to be notified when the value changes.
|
||||
*/
|
||||
export class Watchable<T> {
|
||||
private readonly listeners = new Set<WatchFn<T>>();
|
||||
|
||||
public constructor(private currentValue: T) {}
|
||||
|
||||
public get value(): T {
|
||||
return this.currentValue;
|
||||
}
|
||||
|
||||
public set value(value: T) {
|
||||
if (this.currentValue !== value) {
|
||||
this.currentValue = value;
|
||||
for (const listener of this.listeners) {
|
||||
listener(this.currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public watch(listener: (value: T) => void): void {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public unwatch(listener: (value: T) => void): void {
|
||||
this.listeners.delete(listener);
|
||||
}
|
||||
}
|
||||
@ -13,3 +13,7 @@ export type * from "./models/event";
|
||||
export type * from "./api/custom-components";
|
||||
export type * from "./api/legacy-modules";
|
||||
export type * from "./api/legacy-customisations";
|
||||
export type * from "./api/auth";
|
||||
export type * from "./api/dialog";
|
||||
export type * from "./api/profile";
|
||||
export type * from "./api/navigation";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user