Extend the Module API in prep of restricted-guests module
This commit is contained in:
@@ -4,11 +4,26 @@
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
|
||||||
|
import { ComponentType } from 'react';
|
||||||
import { JSX } from 'react';
|
import { JSX } from 'react';
|
||||||
import { ModuleApi } from '@matrix-org/react-sdk-module-api';
|
import { ModuleApi } from '@matrix-org/react-sdk-module-api';
|
||||||
import { Root } from 'react-dom/client';
|
import { Root } from 'react-dom/client';
|
||||||
import { RuntimeModule } from '@matrix-org/react-sdk-module-api';
|
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)
|
// @alpha @deprecated (undocumented)
|
||||||
export interface AliasCustomisations {
|
export interface AliasCustomisations {
|
||||||
// (undocumented)
|
// (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
|
// Warning: (ae-incompatible-release-tags) The symbol "Api" is marked as @public, but its signature references "LegacyCustomisationsApiExtension" which is marked as @alpha
|
||||||
//
|
//
|
||||||
// @public
|
// @public
|
||||||
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension {
|
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension, DialogApiExtension, AccountAuthApiExtension, ProfileApiExtension {
|
||||||
readonly config: ConfigApi;
|
readonly config: ConfigApi;
|
||||||
createRoot(element: Element): Root;
|
createRoot(element: Element): Root;
|
||||||
// @alpha
|
// @alpha
|
||||||
readonly customComponents: CustomComponentsApi;
|
readonly customComponents: CustomComponentsApi;
|
||||||
readonly i18n: I18nApi;
|
readonly i18n: I18nApi;
|
||||||
|
readonly navigation: NavigationApi;
|
||||||
readonly rootNode: HTMLElement;
|
readonly rootNode: HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +79,7 @@ export interface ConfigApi {
|
|||||||
// @alpha
|
// @alpha
|
||||||
export interface CustomComponentsApi {
|
export interface CustomComponentsApi {
|
||||||
registerMessageRenderer(eventTypeOrFilter: string | ((mxEvent: MatrixEvent) => boolean), renderer: CustomMessageRenderFunction, hints?: CustomMessageRenderHints): void;
|
registerMessageRenderer(eventTypeOrFilter: string | ((mxEvent: MatrixEvent) => boolean), renderer: CustomMessageRenderFunction, hints?: CustomMessageRenderHints): void;
|
||||||
|
registerRoomPreviewBar(renderer: CustomRoomPreviewBarRenderFunction): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @alpha
|
// @alpha
|
||||||
@@ -73,13 +90,49 @@ export type CustomMessageComponentProps = {
|
|||||||
// @alpha
|
// @alpha
|
||||||
export type CustomMessageRenderFunction = (
|
export type CustomMessageRenderFunction = (
|
||||||
props: CustomMessageComponentProps,
|
props: CustomMessageComponentProps,
|
||||||
originalComponent?: (props?: OriginalComponentProps) => React.JSX.Element) => JSX.Element;
|
originalComponent?: (props?: OriginalMessageComponentProps) => React.JSX.Element) => JSX.Element;
|
||||||
|
|
||||||
// @alpha
|
// @alpha
|
||||||
export type CustomMessageRenderHints = {
|
export type CustomMessageRenderHints = {
|
||||||
allowEditingEvent?: boolean;
|
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)
|
// @alpha @deprecated (undocumented)
|
||||||
export interface DirectoryCustomisations {
|
export interface DirectoryCustomisations {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
@@ -216,11 +269,28 @@ export class ModuleLoader {
|
|||||||
start(): Promise<void>;
|
start(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @public
|
||||||
|
export interface NavigationApi {
|
||||||
|
toMatrixToLink(link: string, join?: boolean): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
// @alpha
|
// @alpha
|
||||||
export type OriginalComponentProps = {
|
export type OriginalMessageComponentProps = {
|
||||||
showUrlPreview?: boolean;
|
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)
|
// @alpha @deprecated (undocumented)
|
||||||
export interface RoomListCustomisations<Room> {
|
export interface RoomListCustomisations<Room> {
|
||||||
isRoomVisible?(room: Room): boolean;
|
isRoomVisible?(room: Room): boolean;
|
||||||
|
|||||||
@@ -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.
|
* Properties to alter the render function of the original component.
|
||||||
* @alpha Subject to change.
|
* @alpha Subject to change.
|
||||||
*/
|
*/
|
||||||
export type OriginalComponentProps = {
|
export type OriginalMessageComponentProps = {
|
||||||
/**
|
/**
|
||||||
* Should previews be shown for this event.
|
* Should previews be shown for this event.
|
||||||
* This may be overriden by user preferences.
|
* 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.
|
* 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;
|
) => JSX.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,4 +119,22 @@ export interface CustomComponentsApi {
|
|||||||
renderer: CustomMessageRenderFunction,
|
renderer: CustomMessageRenderFunction,
|
||||||
hints?: CustomMessageRenderHints,
|
hints?: CustomMessageRenderHints,
|
||||||
): void;
|
): 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { ConfigApi } from "./config";
|
||||||
import { I18nApi } from "./i18n";
|
import { I18nApi } from "./i18n";
|
||||||
import { CustomComponentsApi } from "./custom-components";
|
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.
|
* 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.
|
* The API for modules to interact with the application.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiExtension {
|
export interface Api
|
||||||
|
extends LegacyModuleApiExtension,
|
||||||
|
LegacyCustomisationsApiExtension,
|
||||||
|
DialogApiExtension,
|
||||||
|
AccountAuthApiExtension,
|
||||||
|
ProfileApiExtension {
|
||||||
/**
|
/**
|
||||||
* The API to read config.json values.
|
* The API to read config.json values.
|
||||||
* Keys should be scoped to the module in reverse domain name notation.
|
* Keys should be scoped to the module in reverse domain name notation.
|
||||||
@@ -93,6 +102,13 @@ export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiEx
|
|||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
readonly customComponents: CustomComponentsApi;
|
readonly customComponents: CustomComponentsApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API to navigate the application.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
readonly navigation: NavigationApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ReactDOM root for rendering React components.
|
* Create a ReactDOM root for rendering React components.
|
||||||
* Exposed to allow modules to avoid needing to bundle their own ReactDOM.
|
* Exposed to allow modules to avoid needing to bundle their own ReactDOM.
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
}
|
||||||
@@ -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>;
|
||||||
|
}
|
||||||
@@ -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/custom-components";
|
||||||
export type * from "./api/legacy-modules";
|
export type * from "./api/legacy-modules";
|
||||||
export type * from "./api/legacy-customisations";
|
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";
|
||||||
|
|||||||
Reference in New Issue
Block a user